Skip to main content
Block attributes define the data structure and persistence layer for your blocks. They specify what data your block stores and how that data is extracted from saved post content.

Attribute Definition

Attributes are defined in the attributes object of your block configuration. Each attribute has a key and a definition object:
attributes: {
    url: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
        attribute: 'src',
    },
    title: {
        type: 'string',
    },
    size: {
        enum: [ 'large', 'small' ],
    },
}

Attribute Properties

Type Validation

type
string
Specifies the data type. Must be one of:
  • null
  • boolean
  • object
  • array
  • string
  • integer
  • number (same as integer)
attributes: {
    title: {
        type: 'string',
    },
    count: {
        type: 'number',
    },
    isActive: {
        type: 'boolean',
    },
    items: {
        type: 'array',
    },
    settings: {
        type: 'object',
    },
}

Enum Validation

enum
array
Restricts the attribute to a fixed set of allowed values
attributes: {
    size: {
        enum: [ 'large', 'small', 'tiny' ]
    },
    direction: {
        type: 'string',
        enum: [ 'ltr', 'rtl' ]
    }
}

Default Value

default
any
Default value used when no matching content is found
attributes: {
    dropCap: {
        type: 'boolean',
        default: false
    },
    tagName: {
        type: 'string',
        enum: [ 'a', 'button' ],
        default: 'a'
    },
    isStackedOnMobile: {
        type: 'boolean',
        default: true
    }
}

Role

role
string
Designates the conceptual purpose of the attribute:
  • content - User-editable content (enables content-only editing)
  • local - Temporary, non-persistable data (not saved to post content)
attributes: {
    content: {
        type: 'rich-text',
        source: 'rich-text',
        selector: 'p',
        role: 'content',  // Marks as user content
    },
    tempData: {
        type: 'string',
        role: 'local',  // Not saved to database
    }
}

Attribute Sources

The source field determines where and how attribute values are stored and extracted.

No Source (Comment Delimiter)

When no source is specified, data is stored in the block’s comment delimiter:
attributes: {
    title: {
        type: 'string',
        // No source - stored in comment
    }
}
Saved as:
<!-- wp:my-plugin/book {"title":"Hello World"} -->
<div class="wp-block-my-plugin-book">Content</div>
<!-- /wp:my-plugin/book -->

Attribute Source

Extract values from HTML element attributes:
source
'attribute'
Must be used with selector and attribute fields
attributes: {
    url: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
        attribute: 'src',
    },
    alt: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
        attribute: 'alt',
    }
}
Extracts from:
<img src="https://example.com/image.jpg" alt="Description" />
Results in:
{
    url: "https://example.com/image.jpg",
    alt: "Description"
}

Boolean Attributes

For existence checks (e.g., disabled attribute), use type: 'boolean':
attributes: {
    disabled: {
        type: 'boolean',
        source: 'attribute',
        selector: 'button',
        attribute: 'disabled',
    }
}

Text Source

Extract inner text content using textContent:
attributes: {
    caption: {
        type: 'string',
        source: 'text',
        selector: 'figcaption',
    }
}
Extracts from:
<figure>
    <img src="/image.jpg" />
    <figcaption>The inner text of the figcaption element</figcaption>
</figure>
Results in:
{ caption: "The inner text of the figcaption element" }

HTML Source

Extract inner HTML using innerHTML:
attributes: {
    content: {
        type: 'string',
        source: 'html',
        selector: 'figcaption',
    }
}
Extracts from:
<figcaption>The inner text of the <strong>figcaption</strong> element</figcaption>
Results in:
{ content: "The inner text of the <strong>figcaption</strong> element" }

Rich-Text Source

For RichText components that support formatting:
attributes: {
    content: {
        type: 'rich-text',
        source: 'rich-text',
        selector: 'p',
        role: 'content'
    }
}

Query Source

Extract arrays of objects by matching multiple elements:
attributes: {
    images: {
        type: 'array',
        source: 'query',
        selector: 'img',
        query: {
            url: {
                type: 'string',
                source: 'attribute',
                attribute: 'src',
            },
            alt: {
                type: 'string',
                source: 'attribute',
                attribute: 'alt',
            },
        }
    }
}
Extracts from:
<div>
    <img src="https://example.com/large.jpg" alt="large image" />
    <img src="https://example.com/small.jpg" alt="small image" />
</div>
Results in:
{
    images: [
        { url: "https://example.com/large.jpg", alt: "large image" },
        { url: "https://example.com/small.jpg", alt: "small image" }
    ]
}

Real-World Examples

Paragraph Block Attributes

From packages/block-library/src/paragraph/block.json:
{
    "attributes": {
        "content": {
            "type": "rich-text",
            "source": "rich-text",
            "selector": "p",
            "role": "content"
        },
        "dropCap": {
            "type": "boolean",
            "default": false
        },
        "placeholder": {
            "type": "string"
        },
        "direction": {
            "type": "string",
            "enum": [ "ltr", "rtl" ]
        }
    }
}

Button Block Attributes

From packages/block-library/src/button/block.json:
{
    "attributes": {
        "text": {
            "type": "rich-text",
            "source": "rich-text",
            "selector": "a,button",
            "role": "content"
        },
        "url": {
            "type": "string",
            "source": "attribute",
            "selector": "a",
            "attribute": "href",
            "role": "content"
        },
        "linkTarget": {
            "type": "string",
            "source": "attribute",
            "selector": "a",
            "attribute": "target",
            "role": "content"
        },
        "rel": {
            "type": "string",
            "source": "attribute",
            "selector": "a",
            "attribute": "rel",
            "role": "content"
        },
        "backgroundColor": {
            "type": "string"
        },
        "textColor": {
            "type": "string"
        },
        "gradient": {
            "type": "string"
        }
    }
}

Group Block Attributes

From packages/block-library/src/group/block.json:
{
    "attributes": {
        "tagName": {
            "type": "string",
            "default": "div"
        },
        "templateLock": {
            "type": [ "string", "boolean" ],
            "enum": [ "all", "insert", "contentOnly", false ]
        }
    }
}

Using Attributes in Components

In Edit Function

export default function Edit( { attributes, setAttributes } ) {
    const { content, alignment, fontSize } = attributes;

    return (
        <RichText
            value={ content }
            onChange={ ( newContent ) => setAttributes( { content: newContent } ) }
            style={ {
                textAlign: alignment,
                fontSize: fontSize + 'px'
            } }
        />
    );
}

In Save Function

export default function save( { attributes } ) {
    const blockProps = useBlockProps.save();

    return (
        <div { ...blockProps }>
            <img src={ attributes.url } alt={ attributes.alt } />
            <p className="book-author">{ attributes.author }</p>
        </div>
    );
}

Meta Attributes (Deprecated)

Meta attributes are deprecated. Use EntityProvider and related hooks from @wordpress/core-data instead.
Old approach (deprecated):
attributes: {
    author: {
        type: 'string',
        source: 'meta',
        meta: 'author'
    },
}
New approach:
import { useEntityProp } from '@wordpress/core-data';

function Edit() {
    const [ meta, setMeta ] = useEntityProp( 'postType', 'post', 'meta' );
    const author = meta.author;
    
    const updateAuthor = ( newAuthor ) => {
        setMeta( { ...meta, author: newAuthor } );
    };
}

Attribute Selectors

The selector field uses CSS selectors to target elements:
// Tag selector
selector: 'img'

// Class selector
selector: '.book-author'

// ID selector
selector: '#unique-element'

// Attribute selector
selector: 'img[data-id]'

// Descendant selector
selector: '.wp-block-image img'

// Multiple selectors
selector: 'a,button'

Best Practices

Store data in HTML markup rather than comment delimiters. This makes blocks more portable and reduces database overhead.
Always specify the type field to ensure proper validation and prevent data corruption.
Mark user-editable content with role: 'content' to enable content-only editing modes.
Use the default field to ensure your block works even when attributes are undefined.
When an attribute should only accept specific values, use enum for validation.

TypeScript Support

interface BookBlockAttributes {
    title: string;
    author: string;
    pages: number;
    isAvailable: boolean;
    tags: string[];
}

import type { BlockEditProps } from '@wordpress/blocks';

export default function Edit( {
    attributes,
    setAttributes
}: BlockEditProps<BookBlockAttributes> ) {
    // TypeScript now knows the shape of attributes
    const { title, author, pages } = attributes;
}

Migration and Deprecation

When changing attributes, use block deprecation to migrate old content:
deprecated: [
    {
        attributes: {
            // Old attribute definition
            oldName: {
                type: 'string',
            },
        },
        migrate( attributes ) {
            return {
                // Map to new attribute
                newName: attributes.oldName,
            };
        },
        save() {
            // Old save function
        },
    },
]

Next Steps

Block Supports

Enable automatic attributes for common features

Inner Blocks

Build blocks that contain other blocks

Build docs developers (and LLMs) love