---
navigationLabel: Modifiers
order: 4
---

# Modifiers

Popper is built using an extensible core, which provides the foundation used to
deliver all the functionalities offered by the library.

All the useful functionalities provided by the library are implemented as Popper
modifiers. They are plugins, or middlewares, that can hook into the lifecycle of
Popper, and add additional logic to the positioning operations provided by
default by Popper. They effectively "modify" the popper state in some fashion,
adding functionality, hence the term "modifiers".

<x-ad />

## Custom Modifiers

Is it possible to add custom modifiers, written by you, by defining them in the
`options.modifiers` array during a Popper instantation.

### Example modifier

A modifier that logs to the console when it's on the top (not very useful, but
demonstrates each property):

```js
const topLogger = {
  name: 'topLogger',
  enabled: true,
  phase: 'main',
  fn({ state }) {
    if (state.placement === 'top') {
      console.log('Popper is on the top');
    }
  },
};

createPopper(reference, popper, {
  modifiers: [topLogger],
});
```

A modifier is composed of an object with the following properties:

```flow
type Modifier = {|
  // Required properties
  name: string,
  enabled: boolean,
  phase: ModifierPhases,
  fn: (ModifierArguments<Options>) => ?State,

  // Optional properties
  requires?: Array<string>,
  requiresIfExists?: Array<string>,
  effect?: (ModifierArguments<Options>) => ?() => void,
  options?: any,
  data?: {},
|};

type ModifierArguments<Options: Obj> = {
  state: $Shape<State>,
  instance: Instance,
  options: $Shape<Options>,
  name: string,
};
```

### `name`

The name is used as an identifier to make it possible to refer to the modifier
from other parts of the library. For example, you can add an object to the
`options.modifier` array with the `name` property, and the `options` property
populated with some custom options, to override the options of a built-in
modifier.

```js
createPopper(reference, popper, {
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['top', 'bottom'],
      },
    },
  ],
});
```

### `enabled`

If set to `true`, the modifier will be executed during the Popper lifecycle,
otherwise, it will be ignored.

### `phase`

Popper's modifiers lifecycle is divided into 3 core phases: `read`, `main`, and
`write`. This is done to optimize the library so that its access to the DOM is
grouped together rather than scattered around the whole lifecycle.

The modifiers that need to read from the DOM should run in the `read` phase, the
ones that only perform logic with algorithms should live in `main`, and the ones
that write to the DOM should be under `write`.

Note that Popper provides a cache of DOM measurements in its state, so that
modifiers can read them rather than querying the DOM, optimizing the overall
execution time. This means you should rarely need to hook into the `read` phase.

For further granularity if needed, there are 2 other sub-phases: `before` and
`after`. Here is the full list:

- `beforeRead`
- `read`
- `afterRead`
- `beforeMain`
- `main`
- `afterMain`
- `beforeWrite`
- `write`
- `afterWrite`

### `fn`

This is the main function, used to provide the logic to the modifier.

There are cases when you may want to control the Popper lifecycle through a
modifier – for example the `flip` modifier can alter the `placement` option, and
if that happens, Popper is instructed to run all the modifiers again, so that
they can react to the updated placement value. A modifier can reset the
lifecycle by setting `state.reset` to `true`.

### `requires`

Specifies the list of modifiers it depends upon. Popper will execute the
modifiers in the correct order to allow the dependent modifier to access the
data provided by the dependee modifier.

For example, `offset` relies on `popperOffsets` data, since it mutates its
properties.

In short, the modifier depends upon this list of modifiers' **data** to work.

### `requiresIfExists`

Specifies the list of modifiers it depends upon, but only if those modifiers
actually exist.

For example, `preventOverflow` relies on `offset`, but only if `offset` actually
exists, because `offset` mutates the `popperOffsets` data, which
`preventOverflow` needs to read and mutate. If `offset` doesn't exist,
`preventOverflow` will still work as normal.

In short, the modifier depends upon this list of modifiers' **behavior** (or
mutations to dependent data from other modifiers) to work.

### `effect`

This function allows you to execute arbitrary code (effects) before the first
update cycle is ran. Perform effects in the function and return a cleanup
function if necessary:

```js
function effect() {
  // perform side effects
  return () => {
    // cleanup side effects
  };
}
```

Examples where this is useful involve code that is not necessary to be run on
every update, rather only when the instance lifecycle changes (created, updated,
or destroyed):

- The `eventListeners` modifier uses this to add and remove `window`/`document`
  event listeners which is not part of the main modifier update cycle.
- The `arrow` modifier uses this to add the element to `state.elements`. The
  `arrow` modifier is dependent on `preventOverflow` (run after), but
  `preventOverflow` depends on `state.elements.arrow`. Since effects are run
  before the first update cycle, the problem is resolved.

### `options`

This is usually an object with all the properties used to configure the
modifier.

### `data`

This is the initial data provided to `state.modifiersData.<MODIFIER_NAME>`,
which is shared to other modifiers to be read or manipulated.
