Lists
Collapsible
One section that opens and closes under its title, such as nutrition facts under a recipe. The content grows to its measured height with CSS, the closed content is in the server HTML and found by the page search of browsers that support hidden="until-found", and the title is a 44px row on touch screens.
In Spoonjoy
Spoonjoy, a recipe app, is built with Ouro HX (how).
See it live, no sign-in needed: API playground
In its source: app/routes/cookbooks.$id.tsx · app/routes/developers.playground.tsx · app/routes/oauth.authorize.tsx
Install
Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):
npx shadcn@latest init --base base --preset nova --yes --no-monoreponpx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):
npx shadcn@latest add ourostack/ouro-ui/collapsible#v1.2.13Or, with the @ouro namespace set up:
npx shadcn@latest add @ouro/ouro-base @ouro/collapsibleIts tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):
npx shadcn@latest add ourostack/ouro-ui/collapsible#v1.2.13 ourostack/ouro-ui/collapsible-tests#v1.2.13import { Collapsible } from "@/components/ouro/collapsible/collapsible";Paths use shadcn's default @/ alias; the CLI rewrites them to yours.
Example
<Collapsible title="Nutrition facts">
<NutritionTable />
</Collapsible>Use instead when
- Use
Accordioninstead for a stack of such sections. - Use
ShowMoreinstead to cut a long list or text short behind a "Show more" button. - Use
DialogorSheetinstead when the content is a task of its own.
Props
Type: CollapsibleProps.
children(required)- Type:
ReactNode - What shows while it is open.
className- Type:
string - Layout only: margins, width, grid placement (
mt-4). Appearance classes warn in development. defaultOpen- Type:
boolean - Opens it first, when the component keeps its own state.
disabled- Type:
boolean - Keeps it from opening or closing.
onOpenChange- Type:
((open: boolean) => void) - Called with the new state when the person opens or closes it.
open- Type:
boolean - Whether it is open, when you control it. Pair it with
onOpenChange. ref- Type:
Ref<HTMLDivElement> - Reaches the rendered element.
title(required)- Type:
ReactNode - The title, in view whether open or closed. It is the button that opens and closes the content.
Don't use
These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.
isOpen: Not a prop. Ouro UI usesopen:<Collapsible open>.label: Not a prop. Ouro UI usestitle:<Collapsible title="Nutrition facts">.onChange: Not a prop. Ouro UI usesonOpenChange:<Collapsible onOpenChange={(open) => …}>.trigger: Not a prop. The button is drawn for you fromtitle:<Collapsible title="Nutrition facts">.
className is for layout only
Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: Collapsible merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes
Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.
Alignment classes (text-center) warn too: set alignment on a parent element.
Claim sources
- layout-classes: test:registry/ouro/components/ouro/collapsible/collapsible.test.tsx::Collapsible > lets app layout classes win and forwards a ref to the root
verify:testExists(registry/ouro/components/ouro/collapsible/collapsible.test.tsx::Collapsible > lets app layout classes win and forwards a ref to the root)