{"id":154737,"date":"2024-08-09T10:25:01","date_gmt":"2024-08-09T10:25:01","guid":{"rendered":"https:\/\/developer.wordpress.org\/block-editor\/reference-guides\/components\/composite\/"},"modified":"2026-09-04T14:34:04","modified_gmt":"2026-09-04T14:34:04","slug":"composite","status":"publish","type":"blocks-handbook","link":"https:\/\/developer.wordpress.org\/block-editor\/reference-guides\/components\/composite\/","title":{"rendered":"Composite"},"content":{"rendered":"<p><code>Composite<\/code> provides a single tab stop on the page and allows navigation through the focusable descendants with arrow keys. This abstract component is based on the <a href=\"https:\/\/w3c.github.io\/aria\/#composite\">WAI-ARIA Composite Role\u2060<\/a>.<\/p>\n<h2>Usage<\/h2>\n<pre><code class=\"language-jsx\">import { Composite } from '@wordpress\/components';\n\n&lt;Composite&gt;\n  &lt;Composite.Group&gt;\n    &lt;Composite.GroupLabel&gt;Label&lt;\/Composite.GroupLabel&gt;\n    &lt;Composite.Item&gt;Item 1&lt;\/Composite.Item&gt;\n    &lt;Composite.Item&gt;Item 2&lt;\/Composite.Item&gt;\n  &lt;\/CompositeGroup&gt;\n&lt;\/Composite&gt;\n<\/code><\/pre>\n<h2>Components<\/h2>\n<h3><code>Composite<\/code><\/h3>\n<p>Renders a composite widget.<\/p>\n<h4>Props<\/h4>\n<h5><code>activeId<\/code>: <code>string | null<\/code><\/h5>\n<p>The current active item <code>id<\/code>. The active item is the element within the composite widget that has either DOM or virtual focus (in case the <code>virtualFocus<\/code> prop is enabled).<\/p>\n<ul>\n<li><code>null<\/code> represents the base composite element (the one with a <a href=\"https:\/\/w3c.github.io\/aria\/#composite\">composite role<\/a>). Users will be able to navigate out of it using arrow keys.<\/li>\n<li>If <code>activeId<\/code> is initially set to <code>null<\/code>, the base composite element itself will have focus and users will be able to navigate to it using arrow keys.<\/p>\n<\/li>\n<li>\n<p>Required: no<\/p>\n<\/li>\n<\/ul>\n<h5><code>defaultActiveId<\/code>: <code>string | null<\/code><\/h5>\n<p>The composite item id that should be active by default when the composite widget is rendered. If <code>null<\/code>, the composite element itself will have focus and users will be able to navigate to it using arrow keys. If <code>undefined<\/code>, the first enabled item will be focused.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>setActiveId<\/code>: <code>((activeId: string | null | undefined) =&gt; void)<\/code><\/h5>\n<p>A callback that gets called when the <code>activeId<\/code> state changes.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>focusLoop<\/code>: <code>boolean | 'horizontal' | 'vertical' | 'both'<\/code><\/h5>\n<p>Determines how the focus behaves when the user reaches the end of the composite widget.<\/p>\n<p>On one-dimensional composite widgets:<\/p>\n<ul>\n<li><code>true<\/code> loops from the last item to the first item and vice-versa.<\/li>\n<li><code>horizontal<\/code> loops only if <code>orientation<\/code> is <code>horizontal<\/code> or not set.<\/li>\n<li><code>vertical<\/code> loops only if <code>orientation<\/code> is <code>vertical<\/code> or not set.<\/li>\n<li>If <code>activeId<\/code> is initially set to <code>null<\/code>, the composite element will be focused in between the last and first items.<\/li>\n<\/ul>\n<p>On two-dimensional composite widgets (ie. when using <code>CompositeRow<\/code>):<\/p>\n<ul>\n<li><code>true<\/code> loops from the last row\/column item to the first item in the same row\/column and vice-versa. If it&#8217;s the last item in the last row, it moves to the first item in the first row and vice-versa.<\/li>\n<li><code>horizontal<\/code> loops only from the last row item to the first item in the same row.<\/li>\n<li><code>vertical<\/code> loops only from the last column item to the first item in the column row.<\/li>\n<li>If <code>activeId<\/code> is initially set to <code>null<\/code>, vertical loop will have no effect as moving down from the last row or up from the first row will focus on the composite element.<\/li>\n<li>If <code>focusWrap<\/code> matches the value of <code>focusLoop<\/code>, it&#8217;ll wrap between the last item in the last row or column and the first item in the first row or column and vice-versa.<\/p>\n<\/li>\n<li>\n<p>Required: no<\/p>\n<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>focusShift<\/code>: <code>boolean<\/code><\/h5>\n<p><strong>Works only on two-dimensional composite widgets<\/strong>.<\/p>\n<p>If enabled, moving up or down when there&#8217;s no next item or when the next item is disabled will shift to the item right before it.<\/p>\n<ul>\n<li>Required: no<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>focusWrap<\/code>: <code>boolean<\/code><\/h5>\n<p><strong>Works only on two-dimensional composite widgets<\/strong>.<\/p>\n<p>If enabled, moving to the next item from the last one in a row or column<br \/>\nwill focus on the first item in the next row or column and vice-versa.<\/p>\n<ul>\n<li><code>true<\/code> wraps between rows and columns.<\/li>\n<li><code>horizontal<\/code> wraps only between rows.<\/li>\n<li><code>vertical<\/code> wraps only between columns.<\/li>\n<li>If <code>focusLoop<\/code> matches the value of <code>focusWrap<\/code>, it&#8217;ll wrap between the<br \/>\nlast item in the last row or column and the first item in the first row or<br \/>\ncolumn and vice-versa.<\/p>\n<\/li>\n<li>\n<p>Required: no<\/p>\n<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>virtualFocus<\/code>: <code>boolean<\/code><\/h5>\n<p>If enabled, the composite element will act as an <a href=\"https:\/\/www.w3.org\/WAI\/ARIA\/apg\/practices\/keyboard-interface\/#kbd_focus_activedescendant\"><code>aria-activedescendant<\/code><\/a><br \/>\ncontainer instead of <a href=\"https:\/\/www.w3.org\/WAI\/ARIA\/apg\/practices\/keyboard-interface\/#kbd_roving_tabindex\">roving tabindex<\/a>. DOM focus will remain on the composite element while its items receive<br \/>\nvirtual focus.<\/p>\n<p>In both scenarios, the item in focus will carry the <code>data-active-item<\/code> attribute.<\/p>\n<ul>\n<li>Required: no<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>orientation<\/code>: <code>'horizontal' | 'vertical' | 'both'<\/code><\/h5>\n<p>Defines the orientation of the composite widget. If the composite has a single row or column (one-dimensional), the <code>orientation<\/code> value determines which arrow keys can be used to move focus:<\/p>\n<ul>\n<li><code>both<\/code>: all arrow keys work.<\/li>\n<li><code>horizontal<\/code>: only left and right arrow keys work.<\/li>\n<li><code>vertical<\/code>: only up and down arrow keys work.<\/li>\n<\/ul>\n<p>It doesn&#8217;t have any effect on two-dimensional composites.<\/p>\n<ul>\n<li>Required: no<\/li>\n<li>Default: <code>both<\/code><\/li>\n<\/ul>\n<h5><code>rtl<\/code>: <code>boolean<\/code><\/h5>\n<p>Determines how the <code>store<\/code>&#8216;s <code>next<\/code> and <code>previous<\/code> functions will behave. If <code>rtl<\/code> is set to <code>true<\/code>, they will be inverted.<\/p>\n<p>This only affects the composite widget behavior. You still need to set <code>dir=\"rtl\"<\/code> on HTML\/CSS.<\/p>\n<ul>\n<li>Required: no<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>focusable<\/code>: <code>boolean<\/code><\/h5>\n<p>Makes the component a focusable element. When this element gains keyboard focus, it gets a <code>data-focus-visible<\/code> attribute and triggers the <code>onFocusVisible<\/code> prop.<\/p>\n<p>The component supports the <code>disabled<\/code> prop even for those elements not supporting the native <code>disabled<\/code> attribute. Disabled elements may be still accessible via keyboard by using the <code>accessibleWhenDisabled<\/code> prop.<\/p>\n<p>Non-native focusable elements will lose their focusability entirely. However, native focusable elements will retain their inherent focusability.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>disabled<\/code>: <code>boolean<\/code><\/h5>\n<p>Determines if the element is disabled. This sets the <code>aria-disabled<\/code> attribute accordingly, enabling support for all elements, including those that don&#8217;t support the native <code>disabled<\/code> attribute.<\/p>\n<p>This feature can be combined with the <code>accessibleWhenDisabled<\/code> prop to<br \/>\nmake disabled elements still accessible via keyboard.<\/p>\n<p><strong>Note<\/strong>: For this prop to work, the <code>focusable<\/code> prop must be set to<br \/>\n<code>true<\/code>, if it&#8217;s not set by default.<\/p>\n<ul>\n<li>Required: no<\/li>\n<li>Default: <code>false<\/code><\/li>\n<\/ul>\n<h5><code>accessibleWhenDisabled<\/code>: <code>boolean<\/code><\/h5>\n<p>Indicates whether the element should be focusable even when it is<br \/>\n<code>disabled<\/code>.<\/p>\n<p>This is important when discoverability is a concern. For example:<\/p>\n<blockquote><p>\n  A toolbar in an editor contains a set of special smart paste functions<br \/>\n  that are disabled when the clipboard is empty or when the function is not<br \/>\n  applicable to the current content of the clipboard. It could be helpful to<br \/>\n  keep the disabled buttons focusable if the ability to discover their<br \/>\n  functionality is primarily via their presence on the toolbar.\n<\/p><\/blockquote>\n<p>Learn more on <a href=\"https:\/\/www.w3.org\/WAI\/ARIA\/apg\/practices\/keyboard-interface\/#focusabilityofdisabledcontrols\">Focusability of disabled<br \/>\ncontrols<\/a>.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>onFocusVisible<\/code>: <code>(event: SyntheticEvent&lt;HTMLElement&gt;) =&gt; void<\/code><\/h5>\n<p>Custom event handler invoked when the element gains focus through keyboard interaction or a key press occurs while the element is in focus. This is the programmatic equivalent of the <code>data-focus-visible<\/code> attribute.<\/p>\n<p><strong>Note<\/strong>: For this prop to work, the <code>focusable<\/code> prop must be set to <code>true<\/code> if it&#8217;s not set by default.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Group<\/code><\/h3>\n<p>Renders a group element for composite items.<\/p>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.GroupLabel<\/code><\/h3>\n<p>Renders a label in a composite group. This component must be wrapped with <code>Composite.Group<\/code> so the <code>aria-labelledby<\/code> prop is properly set on the composite group element.<\/p>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Item<\/code><\/h3>\n<p>Renders a composite item.<\/p>\n<h5><code>accessibleWhenDisabled<\/code>: <code>boolean<\/code><\/h5>\n<p>Indicates whether the element should be focusable even when it is<br \/>\n<code>disabled<\/code>.<\/p>\n<p>This is important when discoverability is a concern. For example:<\/p>\n<blockquote><p>\n  A toolbar in an editor contains a set of special smart paste functions<br \/>\n  that are disabled when the clipboard is empty or when the function is not<br \/>\n  applicable to the current content of the clipboard. It could be helpful to<br \/>\n  keep the disabled buttons focusable if the ability to discover their<br \/>\n  functionality is primarily via their presence on the toolbar.\n<\/p><\/blockquote>\n<p>Learn more on <a href=\"https:\/\/www.w3.org\/WAI\/ARIA\/apg\/practices\/keyboard-interface\/#focusabilityofdisabledcontrols\">Focusability of disabled<br \/>\ncontrols<\/a>.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Row<\/code><\/h3>\n<p>Renders a composite row. Wrapping <code>Composite.Item<\/code> elements within <code>Composite.Row<\/code> will create a two-dimensional composite widget, such as a grid.<\/p>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Hover<\/code><\/h3>\n<p>Renders an element in a composite widget that receives focus on mouse move and loses focus to the composite base element on mouse leave. This should be combined with the <code>Composite.Item<\/code> component.<\/p>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Typeahead<\/code><\/h3>\n<p>Renders a component that adds typeahead functionality to composite components. Hitting printable character keys will move focus to the next composite item that begins with the input characters.<\/p>\n<h5><code>render<\/code>: <code>RenderProp&lt;React.HTMLAttributes&lt;any&gt; &amp; { ref?: React.Ref&lt;any&gt; | undefined; }&gt; | React.ReactElement&lt;any, string | React.JSXElementConstructor&lt;any&gt;&gt;<\/code><\/h5>\n<p>Allows the component to be rendered as a different HTML element or React component. The value can be a React element or a function that takes in the original component props and gives back a React element with the props merged.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h5><code>children<\/code>: <code>React.ReactNode<\/code><\/h5>\n<p>The contents of the component.<\/p>\n<ul>\n<li>Required: no<\/li>\n<\/ul>\n<h3><code>Composite.Context<\/code><\/h3>\n<p>The React context used by the composite components. It can be used by to access the composite store, and to forward the context when composite sub-components are rendered across portals (ie. <code>SlotFill<\/code> components) that would not otherwise forward the context to the <code>Fill<\/code> children.<\/p>\n","protected":false},"author":0,"featured_media":0,"parent":134435,"menu_order":262,"template":"","meta":{"footnotes":""},"class_list":["post-154737","blocks-handbook","type-blocks-handbook","status-publish","hentry","type-handbook"],"revision_note":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/blocks-handbook\/154737","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/blocks-handbook"}],"about":[{"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/types\/blocks-handbook"}],"version-history":[{"count":9,"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/blocks-handbook\/154737\/revisions"}],"predecessor-version":[{"id":184547,"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/blocks-handbook\/154737\/revisions\/184547"}],"up":[{"embeddable":true,"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/blocks-handbook\/134435"}],"wp:attachment":[{"href":"https:\/\/developer.wordpress.org\/wp-json\/wp\/v2\/media?parent=154737"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}