Disclosure Group

PreviousNext

A grouping of related disclosures, sometimes called an accordion. It supports both single and multiple expanded items.

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupDemo() {
  return (
    <DisclosureGroup className="w-full max-w-xl">
      <Disclosure id="personal">
        <DisclosureHeader>Personal Information</DisclosureHeader>
        <DisclosurePanel>
          Enter your personal details including name, email, and phone number.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="billing">
        <DisclosureHeader>Billing Address</DisclosureHeader>
        <DisclosurePanel>
          Provide your billing address for payment processing.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="shipping">
        <DisclosureHeader>Shipping Information</DisclosureHeader>
        <DisclosurePanel>
          Enter the address where you'd like your order delivered.
        </DisclosurePanel>
      </Disclosure>
    </DisclosureGroup>
  )
}

Installation

pnpm dlx shadcn@latest add disclosure

Usage

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"
<DisclosureGroup>
  <Disclosure id="personal">
    <DisclosureHeader>Personal Information</DisclosureHeader>
    <DisclosurePanel>
      Enter your personal details.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="billing">
    <DisclosureHeader>Billing Address</DisclosureHeader>
    <DisclosurePanel>
      Provide your billing address.
    </DisclosurePanel>
  </Disclosure>
</DisclosureGroup>

Examples

Default

A basic disclosure group with multiple collapsible sections. By default, only one disclosure can be expanded at a time.

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupDemo() {
  return (
    <DisclosureGroup className="w-full max-w-xl">
      <Disclosure id="personal">
        <DisclosureHeader>Personal Information</DisclosureHeader>
        <DisclosurePanel>
          Enter your personal details including name, email, and phone number.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="billing">
        <DisclosureHeader>Billing Address</DisclosureHeader>
        <DisclosurePanel>
          Provide your billing address for payment processing.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="shipping">
        <DisclosureHeader>Shipping Information</DisclosureHeader>
        <DisclosurePanel>
          Enter the address where you'd like your order delivered.
        </DisclosurePanel>
      </Disclosure>
    </DisclosureGroup>
  )
}

Default Expanded

You can set one or more disclosures to be expanded by default using the defaultExpandedKeys prop.

  • Node.js 18 or higher
  • 4GB RAM minimum
  • 10GB available storage

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupDefaultExpanded() {
  return (
    <DisclosureGroup
      defaultExpandedKeys={["system"]}
      className="w-full max-w-xl"
    >
      <Disclosure id="system">
        <DisclosureHeader>System Requirements</DisclosureHeader>
        <DisclosurePanel>
          <ul className="list-disc space-y-1 pl-4">
            <li>Node.js 18 or higher</li>
            <li>4GB RAM minimum</li>
            <li>10GB available storage</li>
          </ul>
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="installation">
        <DisclosureHeader>Installation</DisclosureHeader>
        <DisclosurePanel>
          Run <code className="bg-muted rounded px-1 py-0.5">npm install</code>{" "}
          to install dependencies.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="configuration">
        <DisclosureHeader>Configuration</DisclosureHeader>
        <DisclosurePanel>
          Create a <code className="bg-muted rounded px-1 py-0.5">.env</code>{" "}
          file in the root directory.
        </DisclosurePanel>
      </Disclosure>
    </DisclosureGroup>
  )
}
<DisclosureGroup defaultExpandedKeys={["system"]}>
  <Disclosure id="system">
    <DisclosureHeader>System Requirements</DisclosureHeader>
    <DisclosurePanel>
      <ul className="list-disc pl-4 space-y-1">
        <li>Node.js 18 or higher</li>
        <li>4GB RAM minimum</li>
        <li>10GB available storage</li>
      </ul>
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="installation">
    <DisclosureHeader>Installation</DisclosureHeader>
    <DisclosurePanel>
      Run npm install to install dependencies.
    </DisclosurePanel>
  </Disclosure>
</DisclosureGroup>

Multiple Expanded

By default, opening one disclosure automatically closes others. Use allowsMultipleExpanded to allow multiple disclosures to be open simultaneously.

Our platform includes real-time collaboration, version control, and advanced analytics.

Choose from our flexible plans: Starter ($9/mo), Pro ($29/mo), or Enterprise (custom pricing).

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupMultiple() {
  return (
    <DisclosureGroup
      allowsMultipleExpanded
      defaultExpandedKeys={["features", "pricing"]}
      className="w-full max-w-xl"
    >
      <Disclosure id="features">
        <DisclosureHeader>Features</DisclosureHeader>
        <DisclosurePanel>
          Our platform includes real-time collaboration, version control, and
          advanced analytics.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="pricing">
        <DisclosureHeader>Pricing</DisclosureHeader>
        <DisclosurePanel>
          Choose from our flexible plans: Starter ($9/mo), Pro ($29/mo), or
          Enterprise (custom pricing).
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="support">
        <DisclosureHeader>Support</DisclosureHeader>
        <DisclosurePanel>
          24/7 customer support via email, chat, and phone for all paid plans.
        </DisclosurePanel>
      </Disclosure>
    </DisclosureGroup>
  )
}
<DisclosureGroup
  allowsMultipleExpanded
  defaultExpandedKeys={["features", "pricing"]}
>
  <Disclosure id="features">
    <DisclosureHeader>Features</DisclosureHeader>
    <DisclosurePanel>
      Our platform includes real-time collaboration, version control, and
      advanced analytics.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="pricing">
    <DisclosureHeader>Pricing</DisclosureHeader>
    <DisclosurePanel>
      Choose from our flexible plans: Starter ($9/mo), Pro ($29/mo), or
      Enterprise (custom pricing).
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="support">
    <DisclosureHeader>Support</DisclosureHeader>
    <DisclosurePanel>
      24/7 customer support via email, chat, and phone for all paid plans.
    </DisclosurePanel>
  </Disclosure>
</DisclosureGroup>

Controlled

For more control over the expanded state, use the expandedKeys and onExpandedChange props.

This project aims to build a modern web application using the latest technologies.

"use client"

import { useState } from "react"

import { Button } from "@/components/ui/button"
import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupControlled() {
  const [expandedKeys, setExpandedKeys] = useState<Set<React.Key>>(
    new Set(["overview"])
  )

  return (
    <div className="space-y-4">
      <div className="flex gap-2">
        <Button
          size="sm"
          variant="outline"
          onPress={() => setExpandedKeys(new Set(["overview", "details"]))}
        >
          Expand All
        </Button>
        <Button
          size="sm"
          variant="outline"
          onPress={() => setExpandedKeys(new Set())}
        >
          Collapse All
        </Button>
      </div>
      <DisclosureGroup
        expandedKeys={expandedKeys}
        onExpandedChange={setExpandedKeys}
        className="w-full max-w-xl"
      >
        <Disclosure id="overview">
          <DisclosureHeader>Project Overview</DisclosureHeader>
          <DisclosurePanel>
            This project aims to build a modern web application using the latest
            technologies.
          </DisclosurePanel>
        </Disclosure>
        <Disclosure id="details">
          <DisclosureHeader>Technical Details</DisclosureHeader>
          <DisclosurePanel>
            Built with React, TypeScript, and Tailwind CSS. Uses React Aria for
            accessibility.
          </DisclosurePanel>
        </Disclosure>
        <Disclosure id="timeline">
          <DisclosureHeader>Timeline</DisclosureHeader>
          <DisclosurePanel>
            Phase 1: Q1 2025 - Planning and design
            <br />
            Phase 2: Q2 2025 - Development
            <br />
            Phase 3: Q3 2025 - Testing and launch
          </DisclosurePanel>
        </Disclosure>
      </DisclosureGroup>
    </div>
  )
}
"use client"
 
import { useState } from "react"
import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"
import { Button } from "@/components/ui/button"
 
export default function Example() {
  const [expandedKeys, setExpandedKeys] = useState<Set<React.Key>>(
    new Set(["overview"])
  )
 
  return (
    <div className="space-y-4">
      <div className="flex gap-2">
        <Button
          size="sm"
          variant="outline"
          onPress={() => setExpandedKeys(new Set(["overview", "details"]))}
        >
          Expand All
        </Button>
        <Button
          size="sm"
          variant="outline"
          onPress={() => setExpandedKeys(new Set())}
        >
          Collapse All
        </Button>
      </div>
      <DisclosureGroup
        expandedKeys={expandedKeys}
        onExpandedChange={setExpandedKeys}
      >
        <Disclosure id="overview">
          <DisclosureHeader>Project Overview</DisclosureHeader>
          <DisclosurePanel>
            This project aims to build a modern web application.
          </DisclosurePanel>
        </Disclosure>
        <Disclosure id="details">
          <DisclosureHeader>Technical Details</DisclosureHeader>
          <DisclosurePanel>
            Built with React, TypeScript, and Tailwind CSS.
          </DisclosurePanel>
        </Disclosure>
      </DisclosureGroup>
    </div>
  )
}

Disabled

Individual disclosures can be disabled to prevent user interaction.

import {
  Disclosure,
  DisclosureGroup,
  DisclosureHeader,
  DisclosurePanel,
} from "@/components/ui/disclosure"

export function DisclosureGroupDisabled() {
  return (
    <DisclosureGroup className="w-full max-w-xl">
      <Disclosure id="available">
        <DisclosureHeader>Available Feature</DisclosureHeader>
        <DisclosurePanel>
          This feature is available and can be accessed.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="disabled" isDisabled>
        <DisclosureHeader>Disabled Feature</DisclosureHeader>
        <DisclosurePanel>
          This content is not accessible because the disclosure is disabled.
        </DisclosurePanel>
      </Disclosure>
      <Disclosure id="coming-soon" isDisabled>
        <DisclosureHeader>Coming Soon</DisclosureHeader>
        <DisclosurePanel>
          This feature will be available in a future update.
        </DisclosurePanel>
      </Disclosure>
    </DisclosureGroup>
  )
}
<DisclosureGroup>
  <Disclosure id="available">
    <DisclosureHeader>Available Feature</DisclosureHeader>
    <DisclosurePanel>
      This feature is available and can be accessed.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="disabled" isDisabled>
    <DisclosureHeader>Disabled Feature</DisclosureHeader>
    <DisclosurePanel>
      This content is not accessible because the disclosure is disabled.
    </DisclosurePanel>
  </Disclosure>
  <Disclosure id="coming-soon" isDisabled>
    <DisclosureHeader>Coming Soon</DisclosureHeader>
    <DisclosurePanel>
      This feature will be available in a future update.
    </DisclosurePanel>
  </Disclosure>
</DisclosureGroup>

API Reference

DisclosureGroup

The DisclosureGroup component manages the expanded state of multiple disclosures and handles keyboard navigation between them.

PropTypeDefaultDescription
defaultExpandedKeysIterable<Key>-The initial expanded keys (uncontrolled)
expandedKeysIterable<Key>-The controlled expanded keys
onExpandedChange(keys: Set<Key>) => void-Callback when expanded keys change
allowsMultipleExpandedbooleanfalseWhether multiple disclosures can be expanded at the same time
isDisabledbooleanfalseWhether all disclosures in the group are disabled
classNamestring-CSS class name for the group container

Disclosure

Each Disclosure represents a single collapsible section within the group.

PropTypeDefaultDescription
idKey-Unique identifier for the disclosure (required)
isDisabledbooleanfalseWhether the disclosure is disabled
classNamestring | Function-CSS class name or function for styling

DisclosureHeader

The header contains the trigger button and heading for the disclosure.

PropTypeDefaultDescription
childrenReactNode-Content of the header

DisclosurePanel

The panel contains the collapsible content.

PropTypeDefaultDescription
childrenReactNode-Content to display when expanded
classNamestring | Function-CSS class name or function for styling

Apart from the props above, all components support the props from their corresponding React Aria components. See the React Aria documentation for more details.

Features

  • Accessible - Built on React Aria Components with proper ARIA attributes and keyboard navigation
  • Accordion Pattern - Implements the standard accordion pattern with keyboard support
  • Flexible Expansion - Support for single or multiple expanded items
  • Controlled or Uncontrolled - Works with both controlled and uncontrolled patterns
  • Keyboard Navigation - Full keyboard support with Tab, Enter, and Space keys
  • Animated - Smooth height transitions when expanding/collapsing
  • Disabled State - Individual disclosures can be disabled
  • Searchable - Uses hidden="until-found" for find-in-page support (in supported browsers)

Keyboard Interactions

KeyDescription
TabMove focus to the next disclosure trigger
Shift + TabMove focus to the previous disclosure trigger
EnterToggle the focused disclosure
SpaceToggle the focused disclosure
  • Disclosure - For single collapsible section
  • Tabs - For mutually exclusive content panels
  • Collapsible - For a single collapsible section with animation