All components
Collapsible
Show and hide a region of content behind a trigger, with a bare content slot to style freely.
Custom domains, edge caching, and preview deployments are configured per environment.
1234567891011121314151617import { Collapsible } from "#components/ui/base-ui/collapsible.tsx";import { Button } from "#components/ui/base-ui/button.tsx";
export function Example() { return ( // the engine wires the trigger and animates the panel; the panel slot is // deliberately bare — style it freely via the style prop <Collapsible.Root defaultOpen> <Collapsible.Trigger render={<Button variant="surface" />}> Show advanced options </Collapsible.Trigger> <Collapsible.Panel> Custom domains, edge caching, and preview deployments. </Collapsible.Panel> </Collapsible.Root> );}Install
1npx stylexblocks add collapsibleSource
components/ui/base-ui/collapsible.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657import * as stylex from "@stylexjs/stylex";import { Collapsible as BaseCollapsible } from "@base-ui-components/react/collapsible";import { createSlotRecipeContext } from "#lib/base-ui/create-slot-recipe-context.tsx";import { defineSlotRecipe } from "#lib/recipe-props.ts";import { durations } from '@stylexblocks/ui/tokens/durations.stylex.ts'
const collapsibleContent = stylex.create({ base: { overflow: 'hidden', animationName: { default: null, ':is([data-open], [data-state="open"])': 'expand-height, fade-in', ':is([data-closed], [data-state="closed"])': 'collapse-height, fade-out', }, animationDuration: { default: null, ':is([data-open], [data-state="open"])': durations.moderate, ':is([data-closed], [data-state="closed"])': durations.moderate, }, },})
// The recipe's expand/collapse-height keyframes animate to `var(--height)`// (set by Ark's machine); Base UI measures into its own var, so the panel// aliases it onto `--height` for the shared keyframes to pick up.const chrome = stylex.create({ panel: { "--height": "var(--collapsible-panel-height)", },});
const collapsibleRecipe = defineSlotRecipe({ slots: { content: { styles: collapsibleContent }, }, defaultVariants: {},});
const { withContext } = createSlotRecipeContext(collapsibleRecipe);
/** * Collapsible — Base UI's collapsible machine wearing the collapsible slot * recipe: trigger wiring, height animation hooks, and open state all come * from the engine (Root → Trigger → Panel). The panel slot carries only the * open/close height animation — style the rest freely per use. Every part * composes via `render`. */export const Collapsible = { Root: BaseCollapsible.Root, Trigger: BaseCollapsible.Trigger, Panel: withContext( BaseCollapsible.Panel, () => [collapsibleContent.base, chrome.panel], "CollapsiblePanel", ),};