# Variations

The Block Variations API allows you to define multiple versions (variations) of a block. A block variation differs from the original block by a set of initial attributes or inner blocks. When you insert the block variation into the Editor, these attributes and/or inner blocks are applied.

Variations are an excellent way to create iterations of existing blocks without building entirely new blocks from scratch.

To better understand this API, consider the Embed block. This block contains numerous variations for each type of embeddable content (WordPress, Youtube, etc.). Each Embed block variation shares the same underlying functionality for editing, saving, and so on. Besides the name and descriptive information, the main difference is the `providerNameSlug` attribute. Below is a simplified example of the variations in the Embed block. View the [source code](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/embed/variations.js) for the complete specification.

``` js
variations: [
    {
        name: 'wordpress',
        title: 'WordPress',
        description: __( 'Embed a WordPress post.' ),
        attributes: { providerNameSlug: 'wordpress' },
    },
    {
        name: 'youtube',
        title: 'YouTube',
        description: __( 'Embed a YouTube video.' ),
        attributes: { providerNameSlug: 'youtube' },
    },
],
```

## Defining a block variation

A block variation is defined by an object that can contain the following fields:

- `name` (type `string`) – A unique and machine-readable name.
- `title` (optional, type `string`) – A human-readable variation title.
- `description` (optional, type `string`) – A human-readable variation description.
- `category` (optional, type `string`) – A category classification used in search interfaces to arrange block types by category.
- `keywords` (optional, type `string[]`) – An array of terms (which can be translated) that help users discover the variation while searching.
- `icon` (optional, type `string` \| `Object`) – An icon helping to visualize the variation. It can have the same shape as the block type.
- `attributes` (optional, type `Object`) – Values that override block attributes.
- `innerBlocks` (optional, type `Array[]`) – Initial configuration of nested blocks.
- `innerContent` (optional, type `Array`) – Static HTML fragments interleaved with inner blocks, where `null` entries mark the positions of the inner blocks within the static markup. Only applies to the Custom HTML block.
- `example` (optional, type `Object`) – Provides structured data for the block preview. Set to `undefined` to disable the preview. See the [Block Registration API](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/#example-optional) for more details.
- `scope` (optional, type `WPBlockVariationScope[]`) – Defaults to `block` and `inserter`. The list of scopes where the variation is applicable. Available options include:
  - `block` – Used by blocks to filter specific block variations. `Columns` and `Query` blocks have such variations, which are passed to the [experimental BlockVariationPicker](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-variation-picker/README.md) component. This component handles displaying the variations and allows users to choose one of them.
  - `inserter` – Block variation is shown on the inserter.
  - `transform` – Block variation is shown in the component for variation transformations.
- `isDefault` (optional, type `boolean`) – Defaults to `false`. Indicates whether the current variation is the default one (details below).
- `isActive` (optional, type `Function|string[]`) – A function or an array of block attributes that is used to determine if the variation is active when the block is selected. The function accepts `blockAttributes` and `variationAttributes` (details below).
- `shortcut` (optional, type `Object`) – A keyboard shortcut that applies the variation to the selected block (details below).

<div class="callout callout-info">

You can technically create a block variation without a unique `name`, but this is **not** recommended. A unique `name` allows the Editor to differentiate between your variation and others that may exist. It also allows your variation to be unregistered as needed and has implications for the `isDefault` settings (details below).

</div>

## Creating a block variation

Block variations can be declared during a block’s registration by providing the `variations` key with a proper array of variation objects, as shown in the example above. See the [Block Registration API](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/) for more details.

To create a variation for an existing block, such as a Core block, use `wp.blocks.registerBlockVariation()`. This function accepts the name of the block and the object defining the variation.

``` js
wp.blocks.registerBlockVariation( 'core/embed', {
    name: 'custom-embed',
    attributes: { providerNameSlug: 'custom' },
} );
```

## Registering block variations in PHP

Block variations can also be registered from PHP using the `get_block_type_variations` filter hook. This approach is particularly useful when you need to dynamically generate variations based on registered post types, taxonomies, or other WordPress data.

Here’s an example of how to register a custom variation for the `core/image` block:

``` php
function my_custom_image_variation( $variations, $block_type ) {
    // Only modify variations for the image block
    if ( 'core/image' !== $block_type->name ) {
        return $variations;
    }

    // Add a custom variation
    $variations[] = array(
        'name'        => 'wide-image',
        'title'       => __( 'Wide image', 'textdomain' ),
        'description' => __( 'A wide image', 'textdomain' ),
        'scope'       => array( 'inserter' ),
        'isDefault'   => false,
        'attributes'  => array(
            'align' => 'wide', // Identifies the link type as custom
        ),
    );

    return $variations;
}
add_filter( 'get_block_type_variations', 'my_custom_image_variation', 10, 2 );
```

The `get_block_type_variations` filter is called when variations are requested for a block type. It receives two parameters:\
– `$variations`: An array of currently registered variations for the block type\
– `$block_type`: The full block type object

Note that variations registered through PHP will be merged with any variations registered through JavaScript using `registerBlockVariation()`.

<div class="callout callout-info">

Check the [How to register block variations with PHP](https://developer.wordpress.org/news/2024/03/how-to-register-block-variations-with-php/) blog post for more info about this

</div>

## Removing a block variation

Block variations can also be easily removed. To do so, use `wp.blocks.unregisterBlockVariation()`. This function accepts the name of the block and the `name` of the variation that should be unregistered.

``` js
wp.blocks.unregisterBlockVariation( 'core/embed', 'youtube' );
```

## Block variations versus block styles

The main difference between block styles and block variations is that a block style just applies a CSS class to the block, so it can be styled in an alternative way. See the [Block Styles API](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/) for more details.

If you want to apply initial attributes or inner blocks, this falls into block variation territory. It’s also possible to override the default block style using the `className` attribute when defining a block variation.

``` js
variations: [
    {
        name: 'blue',
        title: __( 'Blue Quote' ),
        isDefault: true,
        attributes: {
            color: 'blue',
            className: 'is-style-blue-quote'
        },
        icon: 'format-quote',
        isActive: ( blockAttributes, variationAttributes ) =>
            blockAttributes.color === variationAttributes.color
    },
],
```

## Using `isDefault`

By default, all variations will show up in the Inserter in addition to the original block type item. However, setting the `isDefault` flag for any variations listed will override the regular block type in the Inserter. This is a great tool for curating the Editor experience to your specific needs.

For example, if you want Media & Text block to display the image on the right by default, you could create a variation like this:

``` js
wp.blocks.registerBlockVariation( 'core/media-text', {
    name: 'media-text-media-right',
    title: __( 'Media & Text' ),
    isDefault: true,
    attributes: {
        mediaPosition: 'right',
    },
} );
```

### Caveats to using `isDefault`

While `isDefault` works great when overriding a block without existing variations, you may run into issues when other variations exist.

If another variation for the same block uses `isDefault`, your variation will not necessarily become the default. The Editor respects the first registered variation with `isDefault`, which might not be yours.

The solution is to unregister the other variation before registering your variation with `isDefault`. This caveat reinforces the recommendation always to provide variations with a unique `name`. Otherwise, the variation cannot be unregistered.

## Using `isActive`

While the `isActive` property is optional, it’s recommended. This API is used by the block editor to check which variation is active, and display the correct variation’s title, icon and description when an instance of the variation is selected in the editor.

If `isActive` is not set, the Editor cannot distinguish between an instance of the original block and your variation, so the original block information will be displayed.

The property can be set to either an array of strings (`string[]`), or a function. It is recommended to use the string array version whenever possible.

The `string[]` version is used to declare which of the block instance’s attributes should be compared to the given variation’s. Each attribute will be checked and the variation will be active if all of them match.

As an example, in the core Embed block, the `providerNameSlug` attribute is used to determine the embed provider (e.g. ‘youtube’ or ‘twitter’). The variations may be declared like this:

``` js
const variations = [
    {
        name: 'twitter',
        title: 'Twitter',
        icon: embedTwitterIcon,
        keywords: [ 'tweet', __( 'social' ) ],
        description: __( 'Embed a tweet.' ),
        patterns: [ /^https?:\/\/(www\.)?twitter\.com\/.+/i ],
        attributes: { providerNameSlug: 'twitter', responsive: true },
    },
    {
        name: 'youtube',
        title: 'YouTube',
        icon: embedYouTubeIcon,
        keywords: [ __( 'music' ), __( 'video' ) ],
        description: __( 'Embed a YouTube video.' ),
        patterns: [
            /^https?:\/\/((m|www)\.)?youtube\.com\/.+/i,
            /^https?:\/\/youtu\.be\/.+/i,
        ],
        attributes: { providerNameSlug: 'youtube', responsive: true },
    },
    // ...
];
```

The `isActive` property would then look like this:

``` js
isActive: [ 'providerNameSlug' ];
```

This will cause the block instance value for `providerNameSlug` to be compared to the value declared in the variation’s declaration (the values in the code snippet above) to determine which embed variation is active.

Nested object paths are also supported since WordPress `6.6.0`. For example, consider a block variation that has a `query` object as an attribute. It is possible to determine if the variation is active solely based on that object’s `postType` property (while ignoring all its other properties):

``` js
isActive: [ 'query.postType' ];
```

The function version of this property accepts a block instance’s `blockAttributes` as the first argument, and the `variationAttributes` declared for a variation as the second argument. These arguments can be used to determine if a variation is active by comparing them and returning a `true` or `false` (indicating whether this variation is inactive for this block instance).

Using the same example for the embed block, the function version would look like this:

``` js
isActive: ( blockAttributes, variationAttributes ) =>
    blockAttributes.providerNameSlug === variationAttributes.providerNameSlug,
```

### Specificity of `isActive` matches

*Note: Improved handling since WordPress `6.6.0`.*

If there are multiple variations whose `isActive` check matches a given block instance, and all of them are string arrays, then the variation with the highest *specificity* will be chosen. Consider the following example:

``` js
wp.blocks.registerBlockVariation( 'core/paragraph', {
    name: 'paragraph-red',
    title: 'Red Paragraph',
    attributes: {
        textColor: 'vivid-red',
    },
    isActive: [ 'textColor' ],
} );

wp.blocks.registerBlockVariation( 'core/paragraph', {
    name: 'paragraph-red-grey',
    title: 'Red/Grey Paragraph',
    attributes: {
        textColor: 'vivid-red',
        backgroundColor: 'cyan-bluish-gray',
    },
    isActive: [ 'textColor', 'backgroundColor' ],
} );
```

If a block instance has attributes `textColor: vivid-red` and `backgroundColor: cyan-bluish-gray`, both variations’ `isActive` criterion will match that block instance. In this case, the more *specific* match will be determined to be the active variation, where specificity is calculated as the length of each `isActive` array. This means that the `Red/Grey Paragraph` will be shown as the active variation.

Note that specificity cannot be determined for a matching variation if its `isActive` property is a function rather than a `string[]`. In this case, the first matching variation will be determined to be the active variation. For this reason, it is generally recommended to use a `string[]` rather than a `function` for the `isActive` property.

## Using `shortcut`

A variation can declare a keyboard shortcut that applies it to the selected block. The shortcut is registered with the editor’s keyboard shortcuts store and listed in the keyboard shortcuts help modal.

The `shortcut` object takes the following parameters:

- `name` (type `string`) – A unique and machine-readable shortcut name, e.g. `core/block-editor/transform-to-heading-2`.
- `description` (type `string`) – A translated description, displayed in the keyboard shortcuts help modal.
- `keyCombination` (type `Object`) – The key combination that triggers the shortcut, as a `character` and an optional `modifier` (one of the modifiers supported by the [`wp-keycodes` package](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-keycodes/), e.g. `access` or `primary`).
- `aliases` (optional, type `Object[]`) – Alternative key combinations that trigger the same shortcut.

For example, the core Heading block gives each of its level variations a shortcut:

``` js
wp.blocks.registerBlockVariation( 'core/heading', {
    name: 'h2',
    title: 'Heading 2',
    attributes: { level: 2 },
    isActive: ( blockAttributes ) => blockAttributes.level === 2,
    shortcut: {
        name: 'core/block-editor/transform-to-heading-2',
        description: __( 'Transform the selected block into a heading 2.' ),
        keyCombination: { modifier: 'access', character: '2' },
    },
} );
```

The shortcut only applies to blocks that are already of the variation’s own block type: it sets the variation’s `attributes` on the selected block, and does nothing when `isActive` reports the variation as already active. In the example above, that is what lets the shortcut change the level of an existing Heading block.

To reach the variation from a *different* block type, declare the same shortcut on a [block transform](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-transforms/#keyboard-shortcuts) that produces this block, giving it the same `name` and a `variationName` pointing back at the variation. The Heading block does both, which is why <span class="kbd">Alt</span>+<span class="kbd">Shift</span>+<span class="kbd">2</span> turns a Paragraph into an H2 as well as changing an existing heading’s level. Declaring one shortcut in several places is expected, as long as every declaration agrees on the key combination and description; the two can never both apply to the same selection.

Shortcuts only apply to blocks that are fully editable, and are ignored for blocks in a restricted editing mode such as content-only editing.

Key combinations are matched globally, so a combination already claimed by another block or by the editor itself will not reliably reach your variation. In development builds a warning is logged when two blocks declare the same combination.