Block attributes provide information about the data stored by a block. Attributes define the structure of your block’s data and how it’s extracted from saved content.
What are Attributes?
Attributes are the structured data needs of a block. They can exist in different forms when serialized, but are declared together under a common interface. For example, rich content, image URLs, background colors, or button titles.
Defining Attributes
Attributes are specified in the attributes field - an object where each key is the attribute name, and the value is the attribute definition.
attributes: {
url: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
},
title: {
type: 'string',
},
size: {
enum: [ 'large', 'small' ],
},
}
Accessing Attributes
Attributes are available in both the edit and save functions:
function YourBlockEdit( { attributes } ) {
return (
<p>
URL: { attributes.url },
Title: { attributes.title },
Size: { attributes.size }
</p>
);
}
Type Validation
The type indicates the type of data stored by the attribute. A type is required unless an enum is provided.
Valid types:
null
boolean
object
array
string
integer
number (same as integer)
attributes: {
isActive: {
type: 'boolean',
default: false,
},
count: {
type: 'number',
default: 0,
},
items: {
type: 'array',
default: [],
},
settings: {
type: 'object',
default: {},
},
}
Enum Validation
An attribute can be restricted to a fixed set of values using enum:
attributes: {
size: {
enum: [ 'large', 'small', 'tiny' ],
default: 'large',
}
}
Attribute Sources
Attribute sources define how attribute values are extracted from saved post content.
When no source is specified, data is stored in the block’s comment delimiter:
attributes: {
title: {
type: 'string',
default: 'Hello World',
}
}
Saved HTML:
<!-- wp:my-plugin/my-block {"title":"Hello World"} -->
<div>Content here</div>
<!-- /wp:my-plugin/my-block -->
Attribute Source
Extract values from HTML element attributes:
attributes: {
url: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
}
}
Saved content:
<div>
<img src="https://example.com/image.jpg" />
</div>
Extracted attribute:
{ "url": "https://example.com/image.jpg" }
Boolean Attributes
For boolean HTML attributes like disabled:
attributes: {
disabled: {
type: 'boolean',
source: 'attribute',
selector: 'button',
attribute: 'disabled',
}
}
Saved content:
<button type="button" disabled>Click Me</button>
Extracted attribute:
Text Source
Extract inner text from markup (uses textContent):
attributes: {
caption: {
type: 'string',
source: 'text',
selector: 'figcaption',
}
}
Saved content:
<figure>
<img src="/image.jpg" />
<figcaption>The inner text of the figcaption element</figcaption>
</figure>
Extracted attribute:
{ "caption": "The inner text of the figcaption element" }
HTML Source
Extract inner HTML from markup (uses innerHTML):
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'figcaption',
}
}
Saved content:
<figcaption>
The inner text of the <strong>figcaption</strong> element
</figcaption>
Extracted attribute:
{ "content": "The inner text of the <strong>figcaption</strong> element" }
Query Source
Extract an array of values from 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',
},
}
}
}
Saved content:
<div>
<img src="https://example.com/large.jpg" alt="large image" />
<img src="https://example.com/small.jpg" alt="small image" />
</div>
Extracted attribute:
{
"images": [
{ "url": "https://example.com/large.jpg", "alt": "large image" },
{ "url": "https://example.com/small.jpg", "alt": "small image" }
]
}
Selectors
The selector can be any valid CSS selector:
// HTML tag
selector: 'img'
// Class
selector: '.my-content'
// ID
selector: '#unique-element'
// Nested
selector: '.wrapper .content'
// Attribute
selector: 'img[data-type="thumbnail"]'
If no selector is specified, the source runs against the block’s root node.
Default Values
Provide default values that are used when the attribute isn’t found in content:
attributes: {
title: {
type: 'string',
default: 'Hello World',
},
count: {
type: 'number',
default: 10,
},
items: {
type: 'array',
default: [
{ url: 'https://example.com/1.jpg', alt: 'image 1' },
{ url: 'https://example.com/2.jpg', alt: 'image 2' }
],
},
settings: {
type: 'object',
default: {
width: 100,
height: 200,
},
},
}
Attribute Roles
The role property designates an attribute’s conceptual type:
Content Role
Marks attributes as user-editable content:
attributes: {
content: {
type: 'string',
source: 'html',
selector: 'p',
role: 'content',
}
}
Blocks with content role attributes may be enabled for privileged editing in special circumstances like content-only locking.
Local Role
Marks attributes as temporary and non-persistable:
attributes: {
temporaryData: {
type: 'string',
role: 'local',
}
}
Attributes with local role are ignored by the Block Serializer and never saved to post content.
Updating Attributes
Use setAttributes to update attribute values in the editor:
edit: ( { attributes, setAttributes } ) => {
const { title, count } = attributes;
return (
<div { ...useBlockProps() }>
<input
value={ title }
onChange={ ( e ) => setAttributes( { title: e.target.value } ) }
/>
<button onClick={ () => setAttributes( { count: count + 1 } ) }>
Increment: { count }
</button>
</div>
);
}
Save Function Requirements
The block is responsible for ensuring attributes with a source field are saved correctly:
save: ( { attributes } ) => {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
{/* url attribute must be in the markup */}
<img src={ attributes.url } />
{/* title and size are saved in comment delimiter automatically */}
</div>
);
}
Attributes without a source are automatically saved in the block comment delimiter.
Complete Example
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
registerBlockType( 'my-plugin/book', {
title: 'Book',
category: 'widgets',
attributes: {
cover: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
},
title: {
type: 'string',
source: 'html',
selector: '.book-title',
role: 'content',
},
author: {
type: 'string',
source: 'text',
selector: '.book-author',
},
pages: {
type: 'number',
default: 0,
},
genre: {
enum: [ 'fiction', 'non-fiction', 'mystery', 'sci-fi' ],
default: 'fiction',
},
},
edit: ( { attributes, setAttributes } ) => {
return (
<div { ...useBlockProps() }>
<img src={ attributes.cover } alt="" />
<input
value={ attributes.title }
onChange={ ( e ) => setAttributes( { title: e.target.value } ) }
/>
<input
value={ attributes.author }
onChange={ ( e ) => setAttributes( { author: e.target.value } ) }
/>
</div>
);
},
save: ( { attributes } ) => {
return (
<div { ...useBlockProps.save() }>
<img src={ attributes.cover } alt="" />
<h2 className="book-title">{ attributes.title }</h2>
<p className="book-author">{ attributes.author }</p>
</div>
);
},
} );
Best Practices
-
Use appropriate sources: Store data in HTML when possible rather than comment delimiters to reduce data storage.
-
Provide defaults: Always provide sensible default values for attributes.
-
Match save and edit: Ensure your save function outputs the correct HTML structure for your attribute sources.
-
Type carefully: Use the correct type for each attribute to ensure proper validation.
-
Document attributes: Add comments to explain complex attribute structures.
Meta attribute sources are deprecated. Use EntityProvider and related hook APIs instead.
For working with post meta, see the Create Meta Block guide.