Skip to content
Liquidify
HomeDocsComponentsExamplesPlayground
⌘K
(opens in new tab)
Liquidify

Accessible React controls with a CSS and SVG material engine.

Product

ComponentsExamplesPlaygroundPackages

Learn

DocumentationGetting startedConceptsAI resources

Project

CommunityShowcaseVersionsGitHub

Independent open-source software. Not affiliated with or endorsed by Apple Inc.

LicenseBrand

Component catalog

Browse the public controls by interaction purpose. Every result links to generated API facts, accessibility behavior, source, and exhaustive stories.

DisclosureGroup

A disclosure widget: a single tappable header (a label + a trailing chevron indicator) that toggles the visibility of arbitrary content beneath it.

import { DisclosureGroup } from "@liquidify/react/disclosure-group"

Overview

Basic Disclosure Group

A focused starting point showing Disclosure Group with its essential configuration.

API

PropTypeDefaultDescription
animatedboolean | undefinedtrueWhen `false`, the expand/collapse roll (and its deferred unmount via {@link Presence}) is suppressed: toggling shows/hides `children` instantly, exactly as under `prefers-reduced-motion`. The chevron still rotates via CSS; kill that per-instance if an instant swap is wanted there too. Used by DatePicker, whose month/year wheel disclosure must not animate.
childrenReactNode—The revealed content (SwiftUI `\@ViewBuilder content:`). Mounted in the DOM only while expanded (unmounted, not merely `hidden`, while collapsed) — supports a nested `<DisclosureGroup>`, which renders its own independent root with no auto-indent. Optional: a childless DisclosureGroup is a pure header toggle whose only effect is its event callbacks (e.g. lazy-loading content in {@link DisclosureGroupProps.onExpandedChange}).
classNamestring | undefined—Optional additional CSS class merged into the glass surface class. The supported per-instance customisation seam: override any `--lq-*` custom property from this class's CSS — the token cascade the engine reads (ADR-0004). No raw inline style is involved, so this stays ADR-0003 clean.
defaultExpandedboolean | undefinedfalseUncontrolled seed for the internal expanded state (ignored once {@link DisclosureGroupProps.expanded} is supplied). SwiftUI's own default is collapsed.
disabledboolean | undefined—When `true`, sets the native `disabled` attribute on the header `<button>`: removed from the tab order, not activatable via pointer or keyboard, dimmed via `--lq-opacity-muted`. The group's current collapsed/expanded content freezes at whatever it was.
expandedboolean | undefined—Controlled expanded state (SwiftUI `isExpanded: Binding<Bool>`). Passing this switches DisclosureGroup to controlled mode: the rendered state always reflects this value and the consumer owns it via {@link DisclosureGroupProps.onExpandedChange}.
iconReactNode<Icon name="chevron-right" tint="accent" />The header's trailing glyph (SwiftUI disclosure indicator). Defaults to a right-pointing chevron `<Icon name="chevron-right" tint="accent" />` that rotates 90° on expand. To use a different glyph or colour, pass your OWN `<Icon>` (any `ReactNode`); it renders inside the rotating `.lq-disclosure-group-chevron` wrapper, so it still animates on toggle.
label
required
ReactNode—The header's label (SwiftUI `titleKey:` / custom label view). A `string | number` routes through the shared `TextLabel` guard into an internal `Text` styled `variant="headline"`, `weight="bold"`, `color="primary"` — the fixed header typography (ADR-0028). To style it differently, pass your OWN `<Text>` (any `ReactNode`), which passes through unwrapped and owns its typography, OR use {@link DisclosureGroupProps.labelProps} to override individual axes while keeping the fixed structure. This is the button's accessible name.
labelPropsLabelProps | undefined—Per-instance typography override for a `string | number` {@link * DisclosureGroupProps.label} (ADR-0028 rule 2, charter §2) — spread last into the header's primary `TextLabel`, so an explicit value here wins over the fixed `variant="headline"`/`weight="bold"`/`color="primary"` defaults. Ignored when `label` is already a `ReactNode` element (e.g. a caller-supplied `<Text>`), which passes through unwrapped and owns its own axes.
onExpandedChange((expanded: boolean) => void) | undefined—Fires with the next boolean on every toggle path — pointer click anywhere in the header row, or `Space` / `Enter` on the focused header button. Always called, in both controlled and uncontrolled modes. The sole semantic callback (charter §1 rule 5) — there is no public click-level prop.
refRef<HTMLDivElement> | undefined—Forwarded ref to the rendered element — the component's native root (or the merged child element on a component that opts into {@link SlottableProps}). Generic over `E` (charter `docs/api-conventions.md` §4 rule 1, default `HTMLElement`) so a component with a polymorphic root (Link's navigation / action mode union, Text's `as`) can instantiate the concrete element per variant instead of leaving every consumer with a widened `Ref<HTMLElement>`. A component that does not narrow simply inherits the `HTMLElement` default — source-compatible with every pre-existing non-generic `extends ControlProps`.
variantDisclosureGroupVariant | undefinedplainMaterial posture of the root.

Guidelines

Do
  • Use Disclosure Group when its semantics match the content or action.
  • Keep labels concise, specific, and consistent with the surrounding interface.
  • Test the component with keyboard navigation, zoom, and both color schemes.
Don't
  • Do not use Disclosure Group as a visual substitute for a different semantic element.
  • Do not rely on color or an icon alone to communicate essential meaning.
  • Do not override the component tokens with fixed values unless the product theme requires it.

Accessibility

DisclosureGroup supports the documented keyboard interactions below.

Keyboard
  • Press Tab to move focus to the control.
  • Use the control's documented activation keys without trapping focus.
  • Provide an accessible name whenever the visible label is absent.

Tokens

NameValue
--lq-color-accent#007aff
--lq-color-label-primaryComponent-defined value
--lq-disclosure-group-gapvar(--lq-space-8)
--lq-disclosure-group-hpadComponent-defined value
--lq-disclosure-group-padvar(--lq-space-16)
--lq-disclosure-group-thumb-hComponent-defined value
--lq-disclosure-group-track-hComponent-defined value
--lq-duration-standard250ms
--lq-easing-standardcubic-bezier(0.25, 0.1, 0.25, 1)
--lq-focus-ring-colorvar(--lq-button-ring, var(--lq-color-accent))var(--lq-toggle-ring, var(--lq-color-accent))var(--lq-slider-ring, var(--lq-color-accent))var(--lq-tint-current, var(--lq-color-accent))
--lq-glass-440.71.15var(--lq-segmented-control-indicator-blur)calc(var(--lq-glass-material-blur) * 8)var(--lq-shadow-presentational)
--lq-radius-20Component-defined value
--lq-radius-221.375rem
--lq-space-0.0625rem0.125rem0.25rem0.5rem0.75rem1rem1.25rem1.5rem2rem2.5rem3rem3.5rem
--lq-space-161rem
--lq-space-20.125rem

Key features

  • Liquid material

    Uses Liquidify surfaces and theme-aware design tokens.

  • Typed API

    Provides a typed React API with generated prop documentation.

  • Accessible by default

    Preserves semantic structure, focus visibility, and assistive-technology state.

Resources

  • Source
  • Markdown
  • JSON
  • Storybook
Components