Status: stable

  • ScrollLock

    View on Storybook

    View source on GitHub

    Import

    import { ScrollLock } from '@wordpress/components';
    

    Examples

    Default

    const Default = () => {
    	const [ isScrollLocked, setScrollLocked ] = useState( false );
    	const toggleLock = () => setScrollLocked( ! isScrollLocked );
    
    	return (
    		<div style={ { height: 1000 } }>
    			<div
    				style={ {
    					overflow: 'auto',
    					height: 240,
    					border: '1px solid lightgray',
    				} }
    			>
    				<StripedBackground>
    					<div>
    						Start scrolling down. Once you scroll to the end of this
    						container with the stripes, the rest of the page will
    						continue scrolling. <code>ScrollLock</code> prevents
    						this "scroll bleed" from happening.
    					</div>
    					<ToggleContainer>
    						<Button
    							__next40pxDefaultSize
    							variant="primary"
    							onClick={ toggleLock }
    						>
    							Toggle Scroll Lock
    						</Button>
    						{ isScrollLocked && <ScrollLock /> }
    						<p>
    							Scroll locked:{ ' ' }
    							<strong>{ isScrollLocked ? 'Yes' : 'No' }</strong>
    						</p>
    					</ToggleContainer>
    				</StripedBackground>
    			</div>
    		</div>
    	);
    };
    
  • TreeSelect

    Generates a hierarchical select input.

    View on Storybook

    View source on GitHub

    Import

    import { TreeSelect } from '@wordpress/components';
    

    Props

    NameTypeDefaultRequiredDescription
    noOptionLabelstring

    If this property is added, an option will be added with this label to represent empty selection.

    onChangeSelectControlSingleSelectionProps[ 'onChange' ]

    A function that receives the value of the new option that is being selected as input.

    treeTree[]

    An array containing the tree objects with the possible nodes the user can select.

    selectedIdSelectControlSingleSelectionProps[ 'value' ]

    The id of the currently selected node.

    Examples

    Default

    const Default = ( props ) => {
    	const [ selection, setSelection ] =
    		useState< ComponentProps< typeof TreeSelect >[ 'selectedId' ] >();
    
    	return (
    		<TreeSelect
    			__next40pxDefaultSize
    			{ ...props }
    			onChange={ setSelection }
    			selectedId={ selection }
    		/>
    	);
    };
    
  • SearchControl

    SearchControl components let users display a search control.

    View on Storybook

    View source on GitHub

    Import

    import { SearchControl } from '@wordpress/components';
    

    Props

    NameTypeDefaultRequiredDescription
    labelunknown__( 'Search' )
    placeholderunknown__( 'Search' )
    hideLabelFromVisionunknowntrue
    sizeunknown'default'

    Examples

    Default

    const Default = ( {
    	onChange,
    	...props
    } ) => {
    	const [ value, setValue ] = useState< string >();
    
    	return (
    		<SearchControl
    			{ ...props }
    			value={ value }
    			onChange={ ( ...changeArgs ) => {
    				setValue( ...changeArgs );
    				onChange( ...changeArgs );
    			} }
    		/>
    	);
    };
    
  • Truncate

    View on Storybook

    View source on GitHub

    Import

    import { __experimentalTruncate as Truncate } from '@wordpress/components';
    

    Examples

    Default

    const Default = () => {
        return <Truncate numberOfLines={2}>{defaultText}</Truncate>;
    };
    

    Truncate by character count

    const CharacterCount = () => {
        return <Truncate limit={23} ellipsizeMode="tail" ellipsis="[---]">{defaultText}</Truncate>;
    };
    
  • SelectControl

    SelectControl allows users to select from a single or multiple option menu. It functions as a wrapper around the browser’s native <select> element.

    View on Storybook

    View source on GitHub

    Import

    import { SelectControl } from '@wordpress/components';
    

    Examples

    Default

    const Default = ( props ) => {
    	const [ selection, setSelection ] = useState< string[] >();
    
    	if ( props.multiple ) {
    		return (
    			<SelectControl
    				__next40pxDefaultSize
    				{ ...props }
    				multiple
    				value={ selection }
    				onChange={ ( value ) => {
    					setSelection( value );
    					props.onChange?.( value );
    				} }
    			/>
    		);
    	}
    
    	return (
    		<SelectControl
    			__next40pxDefaultSize
    			{ ...props }
    			multiple={ false }
    			value={ selection?.[ 0 ] }
    			onChange={ ( value ) => {
    				setSelection( [ value ] );
    				props.onChange?.( value );
    			} }
    		/>
    	);
    };
    

    With Label And Help Text

    const WithLabelAndHelpText = ( props ) => {
    	const [ selection, setSelection ] = useState< string[] >();
    
    	if ( props.multiple ) {
    		return (
    			<SelectControl
    				__next40pxDefaultSize
    				{ ...props }
    				multiple
    				value={ selection }
    				onChange={ ( value ) => {
    					setSelection( value );
    					props.onChange?.( value );
    				} }
    			/>
    		);
    	}
    
    	return (
    		<SelectControl
    			__next40pxDefaultSize
    			{ ...props }
    			multiple={ false }
    			value={ selection?.[ 0 ] }
    			onChange={ ( value ) => {
    				setSelection( [ value ] );
    				props.onChange?.( value );
    			} }
    		/>
    	);
    };
    

    With Custom Children

    As an alternative to the options prop, optgroups and options can be passed in as children for more customizeability.

    const WithCustomChildren = ( props ) => {
    	const [ selection, setSelection ] = useState< string[] >();
    
    	if ( props.multiple ) {
    		return (
    			<SelectControl
    				__next40pxDefaultSize
    				{ ...props }
    				multiple
    				value={ selection }
    				onChange={ ( value ) => {
    					setSelection( value );
    					props.onChange?.( value );
    				} }
    			/>
    		);
    	}
    
    	return (
    		<SelectControl
    			__next40pxDefaultSize
    			{ ...props }
    			multiple={ false }
    			value={ selection?.[ 0 ] }
    			onChange={ ( value ) => {
    				setSelection( [ value ] );
    				props.onChange?.( value );
    			} }
    		/>
    	);
    };
    

    With Prefix

    By default, the prefix is aligned with the edge of the input border, with no padding. If you want to apply standard padding in accordance with the size variant, wrap the element in the <InputControlPrefixWrapper> component.

    const WithPrefix = ( props ) => {
    	const [ selection, setSelection ] = useState< string[] >();
    
    	if ( props.multiple ) {
    		return (
    			<SelectControl
    				__next40pxDefaultSize
    				{ ...props }
    				multiple
    				value={ selection }
    				onChange={ ( value ) => {
    					setSelection( value );
    					props.onChange?.( value );
    				} }
    			/>
    		);
    	}
    
    	return (
    		<SelectControl
    			__next40pxDefaultSize
    			{ ...props }
    			multiple={ false }
    			value={ selection?.[ 0 ] }
    			onChange={ ( value ) => {
    				setSelection( [ value ] );
    				props.onChange?.( value );
    			} }
    		/>
    	);
    };
    

    Minimal

    const Minimal = ( props ) => {
    	const [ selection, setSelection ] = useState< string[] >();
    
    	if ( props.multiple ) {
    		return (
    			<SelectControl
    				__next40pxDefaultSize
    				{ ...props }
    				multiple
    				value={ selection }
    				onChange={ ( value ) => {
    					setSelection( value );
    					props.onChange?.( value );
    				} }
    			/>
    		);
    	}
    
    	return (
    		<SelectControl
    			__next40pxDefaultSize
    			{ ...props }
    			multiple={ false }
    			value={ selection?.[ 0 ] }
    			onChange={ ( value ) => {
    				setSelection( [ value ] );
    				props.onChange?.( value );
    			} }
    		/>
    	);
    };
    
  • UnitControl

    UnitControl allows the user to set a numeric quantity as well as a unit (e.g. px).

    View on Storybook

    View source on GitHub

    Import

    import { UnitControl } from '@wordpress/components';
    

    Examples

    Default

    const Default = () => {
        const [ value, setValue ] = useState< string | undefined >( '10px' );
    
        return (
            <UnitControl
                __next40pxDefaultSize
                onUnitChange={fn()}
                onFocus={fn()}
                onBlur={fn()}
                label="Label"
                value={ value }
                onChange={ ( v, extra ) => {
    				setValue( v );
    				onChange?.( v, extra );
    			} } />
        );
    };
    

    Press Enter To Change

    If the isPressEnterToChange prop is set to true, the onChange callback will not fire while a new value is typed in the input field (you can verify this behavior by inspecting the console’s output).

    const PressEnterToChange = () => {
        const [ value, setValue ] = useState< string | undefined >( '10px' );
    
        return (
            <UnitControl
                __next40pxDefaultSize
                onUnitChange={fn()}
                onFocus={fn()}
                onBlur={fn()}
                isPressEnterToChange
                value={ value }
                onChange={ ( v, extra ) => {
    				setValue( v );
    				onChange?.( v, extra );
    			} } />
        );
    };
    

    Tweaking The Number Input

    Most of NumberControl‘s props can be passed to UnitControl, and they will affect its numeric input field.

    const TweakingTheNumberInput = () => {
        const [ value, setValue ] = useState< string | undefined >( '10px' );
    
        return (
            <UnitControl
                __next40pxDefaultSize
                onUnitChange={fn()}
                onFocus={fn()}
                onBlur={fn()}
                min={0}
                max={100}
                step="any"
                label="Custom label"
                value={ value }
                onChange={ ( v, extra ) => {
    				setValue( v );
    				onChange?.( v, extra );
    			} } />
        );
    };
    

    With Single Unit

    When only one unit is available, the unit selection dropdown becomes static text.

    const WithSingleUnit = () => {
        const [ value, setValue ] = useState< string | undefined >( '10px' );
    
        return (
            <UnitControl
                __next40pxDefaultSize
                onUnitChange={fn()}
                onFocus={fn()}
                onBlur={fn()}
                units={CSS_UNITS.slice( 0, 1 )}
                value={ value }
                onChange={ ( v, extra ) => {
    				setValue( v );
    				onChange?.( v, extra );
    			} } />
        );
    };
    

    With Custom Units

    It is possible to pass a custom list of units. Every time the unit changes, if the isResetValueOnUnitChange is set to true, the input’s quantity is reset to the new unit’s default value.

    const WithCustomUnits = () => {
        const [ value, setValue ] = useState< string | undefined >( '80km' );
    
        return (
            <UnitControl
                __next40pxDefaultSize
                onUnitChange={fn()}
                onFocus={fn()}
                onBlur={fn()}
                isResetValueOnUnitChange
                min={0}
                units={[
                    {
                        value: 'km',
                        label: 'km',
                        default: 1,
                    },
                    {
                        value: 'mi',
                        label: 'mi',
                        default: 1,
                    },
                    {
                        value: 'm',
                        label: 'm',
                        default: 1000,
                    },
                    {
                        value: 'yd',
                        label: 'yd',
                        default: 1760,
                    },
                ]}
                value={ value }
                onChange={ ( v, extra ) => {
    				setValue( v );
    				onChange?.( v, extra );
    			} } />
        );
    };
    
  • Shortcut

    Shortcut component is used to display keyboard shortcuts, and it can be customized with a custom display and aria label if needed.

    View on Storybook

    View source on GitHub

    Import

    import { Shortcut } from '@wordpress/components';
    

    Props

    NameTypeDefaultRequiredDescription
    classNamestring

    Classname to apply to the shortcut.

    shortcutstring | { display: string; ariaLabel: string }

    Shortcut configuration

    Examples

    Default

    const Default = ( props ) => {
    	return <Shortcut shortcut="Ctrl + S" { ...props } />;
    };
    

    With Aria Label

    const WithAriaLabel = ( props ) => {
    	return <Shortcut shortcut="Ctrl + S" { ...props } />;
    };
    
  • VisuallyHidden

    Visually hides content while keeping it accessible to screen readers. Useful when providing context that’s only meaningful to assistive technology.

    Renders a <div> by default. Use the render prop to swap the underlying element while preserving the visually-hidden behavior.

    Composing with other components

    When composing with another component that uses the render prop pattern, keep VisuallyHidden as the host (outer component) and pass the other component via render. This keeps the other component’s HTML element and semantics intact, while VisuallyHidden only adds its hiding styles:

    View on Storybook

    View source on GitHub

    Import

    import { VisuallyHidden } from '@wordpress/ui';
    

    Props

    NameTypeDefaultRequiredDescription
    classNamestring

    CSS class name to apply to the element.

    styleReact.CSSProperties

    CSS style to apply to the element.

    render| ComponentRenderFn< HTMLAttributesWithRef > | React.ReactElement< Record< string, unknown > >

    Replaces the component’s default HTML element using a given React element, or a function that returns a React element.

    childrenReact.ReactNode

    The content to be rendered inside the component.

    Examples

    Default

    const Default = () => (
        <>
            <VisuallyHidden>This should not show.</VisuallyHidden>
            <div>
                This text will <VisuallyHidden>but not inline </VisuallyHidden>
                always show.
            </div>
        </>
    );
    

    With Custom Element

    Use the render prop to change the underlying HTML element. By default, VisuallyHidden renders a <div>. Here it renders a <label> instead, keeping the native label–input association while hiding the label text visually.

    const WithCustomElement = function WithCustomElementStory() {
        const inputId = useId();
        return (
            <>
                { /* eslint-disable-next-line jsx-a11y/label-has-associated-control */ }
                <VisuallyHidden render={ <label htmlFor={ inputId } /> }>
                    Accessible label
                </VisuallyHidden>
                <input
                    id={ inputId }
                    placeholder="This input has a visually hidden label"
                />
            </>
        );
    };
    
  • MenuItemsChoice

    MenuItemsChoice functions similarly to a set of MenuItems, but allows the user to select one option from a set of multiple choices.

    View on Storybook

    View source on GitHub

    Import

    import { MenuItemsChoice } from '@wordpress/components';
    

    Props

    NameTypeDefaultRequiredDescription
    choicesunknown[]

    Array of choices.

    @default []

    valuestringYes

    Value of currently selected choice (should match a value property from a choice in choices).

    onSelect( value: string ) => voidYes

    Callback function to be called with the selected choice when user selects a new choice.

    onHover( value: string | null ) => void() => {}

    Callback function to be called with a choice when user hovers over a new choice (will be empty on mouse leave).

    @default noop

    Examples

    Default

    const Default = ( {
    	onHover,
    	onSelect,
    	choices,
    } ) => {
    	const [ choice, setChoice ] = useState( choices[ 0 ]?.value ?? '' );
    
    	return (
    		<MenuGroup label="Editor">
    			<MenuItemsChoice
    				choices={ choices }
    				value={ choice }
    				onSelect={ ( ...selectArgs ) => {
    					onSelect( ...selectArgs );
    					setChoice( ...selectArgs );
    				} }
    				onHover={ onHover }
    			/>
    		</MenuGroup>
    	);
    };
    
  • Slot

    View on Storybook

    View source on GitHub

    Import

    import { Slot } from '@wordpress/components';
    

    Examples

    Default

    const Default = ( props ) => {
    	return (
    		<SlotFillProvider>
    			<h2>Profile</h2>
    			<p>
    				Name: <Slot { ...props } name="name" />
    			</p>
    			<p>
    				Age: <Slot { ...props } name="age" />
    			</p>
    			<Fill name="name">Grace</Fill>
    			<Fill name="age">33</Fill>
    		</SlotFillProvider>
    	);
    };
    

    With Fill Props

    const WithFillProps = ( props ) => {
    	return (
    		<SlotFillProvider>
    			<h2>Profile</h2>
    			<p>
    				Name:{ ' ' }
    				<Slot
    					{ ...props }
    					name="name"
    					fillProps={ { name: 'Grace' } }
    				/>
    			</p>
    			<p>
    				Age: <Slot { ...props } name="age" fillProps={ { age: 33 } } />
    			</p>
    
    			<Fill name="name">{ ( fillProps ) => fillProps.name }</Fill>
    			<Fill name="age">{ ( fillProps ) => fillProps.age }</Fill>
    		</SlotFillProvider>
    	);
    };
    

    With Slot Children

    const WithSlotChildren = ( props ) => {
    	return (
    		<SlotFillProvider>
    			<h2>Profile</h2>
    			<p>
    				Name:
    				{ /* @ts-expect-error Not supported children for `<Slot />` when `bubblesVirtually` is true. */ }
    				<Slot { ...props } name="name">
    					{ ( fills ) => {
    						return (
    							<span style={ { color: 'red' } }>{ fills }</span>
    						);
    					} }
    				</Slot>
    			</p>
    			<p>
    				Age:
    				{ /* @ts-expect-error Not support children for `<Slot />` when `bubblesVirtually` is true. */ }
    				<Slot { ...props } name="age">
    					{ ( fills ) => {
    						return (
    							<span style={ { color: 'red' } }>{ fills }</span>
    						);
    					} }
    				</Slot>
    			</p>
    			<Fill name="name">Alice</Fill>
    			<Fill name="age">18</Fill>
    		</SlotFillProvider>
    	);
    };
    

    With Context

    const WithContext = ( props ) => {
    	const Context = createContext< string | number >( '' );
    	const ContextFill = ( { name }: { name: string } ) => {
    		const value = useContext( Context );
    		return <Fill name={ name }>{ value }</Fill>;
    	};
    	return (
    		<SlotFillProvider>
    			<h2>Profile</h2>
    			<p>
    				Name: <Slot { ...props } name="name" />
    			</p>
    			<p>
    				Age: <Slot { ...props } name="age" />
    			</p>
    			<Context.Provider value="Grace">
    				<ContextFill name="name" />
    			</Context.Provider>
    			<Context.Provider value={ 33 }>
    				<ContextFill name="age" />
    			</Context.Provider>
    		</SlotFillProvider>
    	);
    };