Collapsible
A single disclosure: a header you press and the block it shows or hides.
Walkthrough
1. Basic
One header, one body. bind:open holds the state; the body grows to its own height and the chevron turns with it.
Karada, Street 62, house 14 — ring twice.
The courier calls from 07xx when they are ten minutes away.
<script lang="ts"> import { Collapsible, Text } from 'omaris'; let open = $state(false);</script><div class="w-full max-w-md"> <Collapsible bind:open variant="outlined" title="Delivery details" supportingText="Tiger Express · today, 2–6 pm" > <div class="flex flex-col gap-2"> <Text variant="body-md">Karada, Street 62, house 14 — ring twice.</Text> <Text variant="body-sm" tone="muted"> The courier calls from 07xx when they are ten minutes away. </Text> </div> </Collapsible></div> 2. States
A leading icon and a count in end for a panel that says how much it holds; filled when it is a thing of its own; disabled with the reason in the supporting line.
No refunds yet.
<script lang="ts"> import { Badge, Collapsible, Switch, Text } from 'omaris'; let open = $state(true); let settings = $state({ spicy: true, vegan: false, delivery: true });</script><div class="flex w-full max-w-md flex-col gap-4"> <Collapsible bind:open variant="filled" title="Filters"> {#snippet icon()} ... {/snippet} {#snippet end()} <Badge size="sm">{Object.values(settings).filter(Boolean).length}</Badge> {/snippet} <div class="flex flex-col gap-3"> <Switch bind:checked={settings.spicy} label="Spicy dishes" /> <Switch bind:checked={settings.vegan} label="Vegan only" /> <Switch bind:checked={settings.delivery} label="Delivers now" /> </div> </Collapsible> <Collapsible variant="outlined" disabled title="Refund history" supportingText="Available once the order is delivered" > <Text variant="body-md" tone="muted">No refunds yet.</Text> </Collapsible></div> 3. Custom trigger
Any button can be the trigger: trigger hands you aria-expanded, aria-controls and the toggle to spread on it. Here, the "More options" under a form's one required field.
<script lang="ts"> import { Button, Collapsible, Input } from 'omaris'; let open = $state(false);</script><div class="flex w-full max-w-sm flex-col gap-2"> <Input label="Restaurant name" value="Beit Baghdad" /> <Collapsible bind:open classes={{ inner: 'flex flex-col gap-4 px-0 pt-2' }}> {#snippet trigger(props)} <Button variant="text" size="sm" {...props}> {open ? 'Fewer options' : 'More options'} <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" class={[ 'transition-[rotate] duration-300 ease-emphasized motion-reduce:transition-none', open && 'rotate-180' ]} > <path d="m6 9 6 6 6-6" stroke-linecap="round" stroke-linejoin="round" /> </svg> </Button> {/snippet} <Input label="Slug" value="beit-baghdad" /> <Input label="WhatsApp number" value="0770 123 4567" /> </Collapsible></div> 4. Overridden
Every part is reachable: class for the root, classes for the trigger, chevron and body. headingLevel makes the trigger a real heading for a disclosure that titles a section.
<script lang="ts"> import { Collapsible } from 'omaris';</script><div class="w-full max-w-md"> <Collapsible open headingLevel={3} variant="outlined" title="Release notes" supportingText="v2.4.0" class="rounded-shape-2xl border-primary" classes={{ trigger: 'bg-primary-container text-primary-container-foreground', supporting: 'text-primary-container-foreground/80', chevron: 'text-primary-container-foreground', inner: 'pt-4 font-mono text-xs' }} > Faster menus, Kurdish plurals, and a lighter spinner. </Collapsible></div>