Foundation components for organizing content and creating collapsible sections with full accessibility support.
Collapsible content sections with keyboard navigation and ARIA compliance.
/**
* Groups all parts of the accordion. Renders a div element.
*/
interface AccordionRootProps {
/** The controlled value of the item(s) that should be expanded */
value?: AccordionValue;
/** The uncontrolled value of the item(s) that should be initially expanded */
defaultValue?: AccordionValue;
/** Whether the component should ignore user interaction */
disabled?: boolean;
/** Allows browser's built-in page search to find and expand panel contents */
hiddenUntilFound?: boolean;
/** Whether to keep the element in the DOM while the panel is closed */
keepMounted?: boolean;
/** Whether to loop keyboard focus back to the first item when end is reached */
loop?: boolean;
/** Event handler called when an accordion item is expanded or collapsed */
onValueChange?: (value: AccordionValue, eventDetails: AccordionRoot.ChangeEventDetails) => void;
/** Whether multiple items can be open at the same time */
openMultiple?: boolean;
/** The visual orientation of the accordion */
orientation?: 'horizontal' | 'vertical';
}
/**
* Individual accordion item container
*/
interface AccordionItemProps {
/** The unique value for this accordion item */
value: string | number;
/** Whether the component should ignore user interaction */
disabled?: boolean;
}
/**
* Header for accordion item - provides context for the trigger
*/
interface AccordionHeaderProps {
/** Standard HTML props for header element */
}
/**
* Clickable trigger for accordion item
*/
interface AccordionTriggerProps {
/** Whether the component should ignore user interaction */
disabled?: boolean;
}
/**
* Collapsible content panel
*/
interface AccordionPanelProps {
/** Whether to keep the element in the DOM while closed */
keepMounted?: boolean;
}
// Type definitions
type AccordionValue = (string | number | null)[];
namespace AccordionRoot {
interface State {
value: AccordionValue;
disabled: boolean;
orientation: 'horizontal' | 'vertical';
}
type ChangeEventReason = 'none';
interface ChangeEventDetails {
isCanceled: boolean;
}
}Usage Example:
import {
AccordionRoot,
AccordionItem,
AccordionHeader,
AccordionTrigger,
AccordionPanel
} from "@base-ui-components/react/accordion";
function FAQAccordion() {
const [openItems, setOpenItems] = React.useState<string[]>(['faq-1']);
return (
<AccordionRoot
value={openItems}
onValueChange={(value) => setOpenItems(value)}
openMultiple={true}
orientation="vertical"
>
<AccordionItem value="faq-1">
<AccordionHeader>
<AccordionTrigger>
What is Base UI?
</AccordionTrigger>
</AccordionHeader>
<AccordionPanel>
Base UI is a library of headless React components that provide
accessibility and functionality without styling.
</AccordionPanel>
</AccordionItem>
<AccordionItem value="faq-2">
<AccordionHeader>
<AccordionTrigger>
How do I style the components?
</AccordionTrigger>
</AccordionHeader>
<AccordionPanel>
You can style Base UI components using CSS, CSS-in-JS, Tailwind,
or any other styling solution.
</AccordionPanel>
</AccordionItem>
</AccordionRoot>
);
}Simple show/hide content container with smooth animations support.
/**
* Main collapsible container that manages open/closed state
*/
interface CollapsibleRootProps {
/** Whether the collapsible is open (controlled) */
open?: boolean;
/** Whether the collapsible is initially open (uncontrolled) */
defaultOpen?: boolean;
/** Whether the component should ignore user interaction */
disabled?: boolean;
/** Event handler called when the open state changes */
onOpenChange?: (open: boolean, eventDetails: CollapsibleRoot.ChangeEventDetails) => void;
}
/**
* Toggle trigger for the collapsible content
*/
interface CollapsibleTriggerProps {
/** Whether the component should ignore user interaction */
disabled?: boolean;
}
/**
* Collapsible content panel
*/
interface CollapsiblePanelProps {
/** Whether to keep the element in the DOM while closed */
keepMounted?: boolean;
}
namespace CollapsibleRoot {
interface State {
open: boolean;
disabled: boolean;
}
type ChangeEventReason = 'none';
interface ChangeEventDetails {
isCanceled: boolean;
}
}Usage Example:
import {
CollapsibleRoot,
CollapsibleTrigger,
CollapsiblePanel
} from "@base-ui-components/react/collapsible";
function DetailsSection() {
const [isOpen, setIsOpen] = React.useState(false);
return (
<CollapsibleRoot
open={isOpen}
onOpenChange={setIsOpen}
>
<CollapsibleTrigger>
{isOpen ? 'Hide' : 'Show'} Details
</CollapsibleTrigger>
<CollapsiblePanel>
<div>
This content can be shown or hidden using the trigger above.
The panel smoothly animates in and out when toggled.
</div>
</CollapsiblePanel>
</CollapsibleRoot>
);
}Tab navigation component with keyboard support and flexible orientation.
/**
* Main tabs container that manages the selected tab state
*/
interface TabsRootProps {
/** The controlled value of the selected tab */
value?: string;
/** The uncontrolled value of the initially selected tab */
defaultValue?: string;
/** The visual orientation of the tabs */
orientation?: 'horizontal' | 'vertical';
/** Event handler called when the selected tab changes */
onValueChange?: (value: string, eventDetails: TabsRoot.ChangeEventDetails) => void;
}
/**
* Container for tab buttons
*/
interface TabsListProps {
/** Whether to loop keyboard focus from last to first tab */
loop?: boolean;
}
/**
* Individual tab button
*/
interface TabsTabProps {
/** The unique value for this tab */
value: string;
/** Whether the tab should ignore user interaction */
disabled?: boolean;
}
/**
* Visual indicator for the active tab (optional)
*/
interface TabsIndicatorProps {
/** Render function for custom indicator positioning */
render?: (props: { activeTabRect: DOMRect | null }) => React.ReactNode;
}
/**
* Tab content panel
*/
interface TabsPanelProps {
/** The value of the tab this panel corresponds to */
value: string;
/** Whether to keep the element in the DOM while not active */
keepMounted?: boolean;
}
namespace TabsRoot {
interface State {
value: string;
orientation: 'horizontal' | 'vertical';
}
type ChangeEventReason = 'click' | 'keyboard';
interface ChangeEventDetails {
isCanceled: boolean;
}
}Usage Example:
import {
TabsRoot,
TabsList,
TabsTab,
TabsIndicator,
TabsPanel
} from "@base-ui-components/react/tabs";
function ProfileTabs() {
return (
<TabsRoot defaultValue="profile" orientation="horizontal">
<TabsList>
<TabsTab value="profile">Profile</TabsTab>
<TabsTab value="settings">Settings</TabsTab>
<TabsTab value="notifications" disabled>Notifications</TabsTab>
<TabsIndicator />
</TabsList>
<TabsPanel value="profile">
<h2>Profile Information</h2>
<p>Manage your profile details here.</p>
</TabsPanel>
<TabsPanel value="settings">
<h2>Settings</h2>
<p>Configure your application preferences.</p>
</TabsPanel>
<TabsPanel value="notifications">
<h2>Notifications</h2>
<p>Manage your notification preferences.</p>
</TabsPanel>
</TabsRoot>
);
}