Introduction to components
The @wordpress/components package provides a library of generic WordPress components for creating common UI elements shared between screens and features of the WordPress dashboard.
These components are designed to be reusable, accessible, and consistent with WordPress design patterns.
Installation
Install the components package:
npm install @wordpress/components --save
This package requires an ES2015+ environment. Use the polyfill from @wordpress/babel-preset-default if needed.
Basic usage
Import components from the package root:
import { Button } from '@wordpress/components' ;
export default function MyButton () {
return < Button > Click Me! </ Button > ;
}
Loading component styles
Many components include CSS styles that must be loaded for proper appearance.
In WordPress
Add the wp-components stylesheet as a dependency:
wp_enqueue_style (
'my-plugin-style' ,
'path/to/my-style.css' ,
array ( 'wp-components' )
);
In non-WordPress projects
Link directly to the built stylesheet:
import '@wordpress/components/build-style/style.css' ;
The file is located at node_modules/@wordpress/components/build-style/style.css.
Component categories
The components package includes various UI elements:
Button - Buttons with various styles and sizes
TextControl - Text input fields
TextareaControl - Multiline text areas
CheckboxControl - Checkbox inputs
RadioControl - Radio button groups
SelectControl - Dropdown selects
ToggleControl - Toggle switches
Layout Components
Panel - Collapsible panel containers
PanelBody - Panel sections
PanelRow - Panel rows
Card - Card containers
CardBody - Card content areas
Feedback Components
Notice - User notifications
Snackbar - Temporary notifications
Spinner - Loading indicators
Placeholder - Content placeholders
Advanced Components
Popover - Floating popovers
Modal - Modal dialogs
Dropdown - Dropdown menus
ColorPicker - Color selection
DatePicker - Date selection
Block editor components
The @wordpress/block-editor package provides specialized components for the block editor.
Components in @wordpress/block-editor are customized for editor use. Use @wordpress/components for general-purpose UI unless building an editor.
Key block editor components
import {
BlockEditorProvider ,
BlockList ,
BlockCanvas ,
BlockInspector ,
BlockControls ,
InspectorControls ,
InnerBlocks ,
RichText ,
MediaPlaceholder ,
URLInput ,
} from '@wordpress/block-editor' ;
Component examples
import { Button } from '@wordpress/components' ;
import { useState } from '@wordpress/element' ;
function Example () {
const [ isLoading , setIsLoading ] = useState ( false );
return (
< div >
< Button variant = "primary" onClick = { () => setIsLoading ( true ) } >
Primary Button
</ Button >
< Button variant = "secondary" >
Secondary Button
</ Button >
< Button variant = "tertiary" isBusy = { isLoading } >
{ isLoading ? 'Loading...' : 'Tertiary Button' }
</ Button >
</ div >
);
}
Panel components
import { Panel , PanelBody , PanelRow , TextControl } from '@wordpress/components' ;
function SettingsPanel () {
return (
< Panel >
< PanelBody title = "General Settings" initialOpen = { true } >
< PanelRow >
< TextControl
label = "Site Title"
value = { siteTitle }
onChange = { setSiteTitle }
/>
</ PanelRow >
< PanelRow >
< TextControl
label = "Tagline"
value = { tagline }
onChange = { setTagline }
/>
</ PanelRow >
</ PanelBody >
< PanelBody title = "Advanced Settings" initialOpen = { false } >
< PanelRow >
{ /* Advanced settings */ }
</ PanelRow >
</ PanelBody >
</ Panel >
);
}
Modal component
import { Button , Modal } from '@wordpress/components' ;
import { useState } from '@wordpress/element' ;
function ModalExample () {
const [ isOpen , setIsOpen ] = useState ( false );
return (
<>
< Button onClick = { () => setIsOpen ( true ) } >
Open Modal
</ Button >
{ isOpen && (
< Modal
title = "My Modal"
onRequestClose = { () => setIsOpen ( false ) }
>
< p > Modal content goes here. </ p >
< Button variant = "primary" onClick = { () => setIsOpen ( false ) } >
Close
</ Button >
</ Modal >
) }
</>
);
}
ColorPicker component
import { ColorPicker } from '@wordpress/components' ;
import { useState } from '@wordpress/element' ;
function ColorExample () {
const [ color , setColor ] = useState ( '#f00' );
return (
< div >
< ColorPicker
color = { color }
onChangeComplete = { ( value ) => setColor ( value . hex ) }
/>
< p > Selected color: { color } </ p >
</ div >
);
}
Popover system
By default, Popover components render in an element appended to the document body.
Controlling popover placement
Use Popover.Slot to control where popovers render:
import { Popover , SlotFillProvider } from '@wordpress/components' ;
import { MyComponentWithPopover } from './my-component' ;
const App = () => (
< SlotFillProvider >
< MyComponentWithPopover />
< Popover.Slot />
</ SlotFillProvider >
);
Wrap your app with SlotFillProvider and add Popover.Slot where you want popovers to render.
TypeScript usage
The package exports TypeScript types for components. Extract props types using React.ComponentProps:
import type { ComponentProps } from 'react' ;
import { Button } from '@wordpress/components' ;
export default function MyButton ( props : ComponentProps < typeof Button > ) {
return < Button { ... props } > Click Me! </ Button > ;
}
Block editor specific components
The @wordpress/block-editor package provides components designed specifically for block development:
RichText component
For editable rich text content:
import { RichText , useBlockProps } from '@wordpress/block-editor' ;
function Edit ( { attributes , setAttributes } ) {
const blockProps = useBlockProps ();
return (
< RichText
{ ... blockProps }
tagName = "p"
value = { attributes . content }
onChange = { ( content ) => setAttributes ( { content } ) }
placeholder = "Enter text..."
/>
);
}
InspectorControls
For block sidebar settings:
import { InspectorControls } from '@wordpress/block-editor' ;
import { PanelBody , RangeControl } from '@wordpress/components' ;
function Edit ( { attributes , setAttributes } ) {
return (
<>
< InspectorControls >
< PanelBody title = "Settings" >
< RangeControl
label = "Columns"
value = { attributes . columns }
onChange = { ( columns ) => setAttributes ( { columns } ) }
min = { 1 }
max = { 6 }
/>
</ PanelBody >
</ InspectorControls >
{ /* Block content */ }
</>
);
}
BlockControls
For block toolbar controls:
import { BlockControls , AlignmentToolbar } from '@wordpress/block-editor' ;
function Edit ( { attributes , setAttributes } ) {
return (
<>
< BlockControls >
< AlignmentToolbar
value = { attributes . align }
onChange = { ( align ) => setAttributes ( { align } ) }
/>
</ BlockControls >
{ /* Block content */ }
</>
);
}
InnerBlocks
For nested block structures:
import { InnerBlocks , useBlockProps } from '@wordpress/block-editor' ;
function Edit () {
const blockProps = useBlockProps ();
return (
< div { ... blockProps } >
< InnerBlocks
allowedBlocks = { [ 'core/paragraph' , 'core/image' ] }
template = { [
[ 'core/paragraph' , { placeholder: 'Add content...' } ],
] }
/>
</ div >
);
}
function Save () {
const blockProps = useBlockProps . save ();
return (
< div { ... blockProps } >
< InnerBlocks.Content />
</ div >
);
}
The InnerBlocks API governs child block usage and enables hierarchical block structures.
Block hooks
The @wordpress/block-editor package provides essential hooks:
useBlockProps
Marks an element as a block wrapper:
import { useBlockProps } from '@wordpress/block-editor' ;
function Edit () {
const blockProps = useBlockProps ( {
className: 'my-custom-class' ,
style: {
color: '#222' ,
backgroundColor: '#eee' ,
},
} );
return < div { ... blockProps } > Block content </ div > ;
}
Use of useBlockProps on the outermost element is required for blocks using API version 2 or higher.
useInnerBlocksProps
Marks an element as an inner blocks wrapper:
import { useBlockProps , useInnerBlocksProps } from '@wordpress/block-editor' ;
function Edit () {
const blockProps = useBlockProps ();
const innerBlocksProps = useInnerBlocksProps ( blockProps , {
allowedBlocks: [ 'core/paragraph' ],
} );
return < div { ... innerBlocksProps } /> ;
}
useBlockEditContext
Access block edit context:
import { useBlockEditContext } from '@wordpress/block-editor' ;
function MyComponent () {
const { name , isSelected , clientId } = useBlockEditContext ();
return (
< div >
Block: { name }
Selected: { isSelected ? 'Yes' : 'No' }
ID: { clientId }
</ div >
);
}
Component documentation
Comprehensive component documentation and interactive examples are available in Storybook:
Accessibility
WordPress components follow accessibility best practices:
Keyboard navigation support
ARIA attributes for screen readers
Focus management
Color contrast compliance
Semantic HTML structure
Always test your components with keyboard navigation and screen readers to ensure accessibility.
Using components in WordPress
When building WordPress plugins, enqueue component dependencies:
function my_plugin_enqueue_scripts () {
wp_enqueue_script (
'my-plugin-script' ,
plugins_url ( 'build/index.js' , __FILE__ ),
array ( 'wp-components' , 'wp-element' , 'wp-i18n' ),
'1.0.0' ,
true
);
wp_enqueue_style (
'my-plugin-style' ,
plugins_url ( 'build/style.css' , __FILE__ ),
array ( 'wp-components' ),
'1.0.0'
);
}
add_action ( 'admin_enqueue_scripts' , 'my_plugin_enqueue_scripts' );
Access components via the wp global:
const { Button } = wp . components ;
const { render } = wp . element ;
function MyApp () {
return < Button > Click Me! </ Button > ;
}
render ( < MyApp /> , document . getElementById ( 'my-app' ) );
Component status and transitions
The components package is evolving:
WordPress is rewriting global components for the new @wordpress/ui package. However, this is work in progress—continue using @wordpress/components until further notice.
Check component status in Storybook documentation for up-to-date usage guidance. The Storybook status is the most accurate signal, above experimental tags or prefixes.
For editing dataset items, consider using DataForm from @wordpress/dataviews:
import { DataForm } from '@wordpress/dataviews' ;
function EditForm ( { data , onChange } ) {
return (
< DataForm
data = { data }
fields = { fields }
onChange = { onChange }
/>
);
}
For validation, use validated form components:
import { ValidatedTextControl } from '@wordpress/components/validated-form-controls' ;
function MyForm () {
return (
< ValidatedTextControl
label = "Email"
value = { email }
onChange = { setEmail }
validation = { ( value ) => {
if ( ! value . includes ( '@' ) ) {
return 'Please enter a valid email' ;
}
} }
/>
);
}
Best practices
Use semantic components - Choose components that match your intent
Load required styles - Always enqueue component stylesheets
Follow accessibility patterns - Use ARIA labels and keyboard navigation
Check component status - Verify component stability in Storybook
Use TypeScript types - Leverage TypeScript for type safety
Test interactivity - Verify keyboard and screen reader support
Manage dependencies - Properly declare script dependencies
Use SlotFill for popovers - Control popover rendering locations
Next steps