DisclosureGroup

Container that manages multiple Disclosure items with coordinated expanded states

Import

import {DisclosureGroup} from '@heroui/react';

Usage

Scan this QR code with your camera app to preview the HeroUI native components.

Expo Go QR Code

Expo must be installed on your device.

"use client";

import {Button, Disclosure, DisclosureGroup, Separator} from "@heroui/react";
import {Icon} from "@iconify/react";
import React from "react";
import {cnBase} from "tailwind-variants";

export function Basic() {
  const [expandedKeys, setExpandedKeys] = React.useState(new Set<string | number>(["preview"]));

  return (
    <div className="w-full max-w-md">
      <div className="flex flex-col gap-4 bg-transparent p-4">
        <DisclosureGroup expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
          <Disclosure aria-label="Preview HeroUI Native" id="preview">
            <Disclosure.Heading>
              <Button
                slot="trigger"
                variant={expandedKeys.has("preview") ? "secondary" : "tertiary"}
                className={cnBase("w-full border-none", {
                  "bg-transparent": !expandedKeys.has("preview"),
                })}
              >
                <div className="flex w-full items-center justify-start gap-2">
                  <Icon icon="gravity-ui:qr-code" />
                  Preview HeroUI Native
                </div>
                <Disclosure.Indicator className="text-muted" />
              </Button>
            </Disclosure.Heading>
            <Disclosure.Content>
              <Disclosure.Body className="mx-2 flex flex-col items-center gap-2 p-4 text-center">
                <p className="text-muted text-sm">
                  Scan this QR code with your camera app to preview the HeroUI native components.
                </p>
                <img
                  alt="Expo Go QR Code"
                  className="max-w-54 aspect-square w-full object-cover"
                  src="https://raw.githubusercontent.com/heroui-inc/heroui-native/refs/heads/alpha/expo-go-qr.png"
                />
                <p className="text-muted text-sm">Expo must be installed on your device.</p>
                <Button className="mt-4" variant="primary">
                  <Icon className="[&_path]:fill-accent-foreground" icon="logos:expo-icon" />
                  Preview on Expo Go
                </Button>
              </Disclosure.Body>
            </Disclosure.Content>
          </Disclosure>
          <Separator className="my-2" />
          <Disclosure id="download">
            <Disclosure.Heading aria-label="Download HeroUI Native">
              <Button
                slot="trigger"
                variant={expandedKeys.has("download") ? "secondary" : "tertiary"}
                className={cnBase("w-full border-none", {
                  "bg-transparent": !expandedKeys.has("download"),
                })}
              >
                <div className="flex w-full items-center justify-start gap-2">
                  <Icon icon="tabler:brand-apple-filled" />
                  Download App
                </div>
                <Disclosure.Indicator className="text-muted" />
              </Button>
            </Disclosure.Heading>
            <Disclosure.Content>
              <Disclosure.Body className="mx-2 flex flex-col items-center gap-2 p-4 text-center">
                <p className="text-muted text-sm">
                  Download the HeroUI native app to explore our mobile components directly on your
                  device.
                </p>
                <img
                  alt="App Store QR Code"
                  className="max-w-54 aspect-square w-full object-cover"
                  src="https://raw.githubusercontent.com/heroui-inc/heroui-native/refs/heads/alpha/expo-go-qr.png"
                />
                <p className="text-muted text-sm">Available on iOS and Android devices.</p>
                <Button className="mt-4" variant="primary">
                  <Icon icon="tabler:brand-apple-filled" />
                  Download on App Store
                </Button>
              </Disclosure.Body>
            </Disclosure.Content>
          </Disclosure>
        </DisclosureGroup>
      </div>
    </div>
  );
}

Controlled

You can control which disclosures are expanded with external navigation controls using the expandedKeys and onExpandedChange props.

HeroUI Native

Scan this QR code with your camera app to preview the HeroUI native components.

Expo Go QR Code

Expo must be installed on your device.

"use client";

import {
  Button,
  Disclosure,
  DisclosureGroup,
  Separator,
  useDisclosureGroupNavigation,
} from "@heroui/react";
import {Icon} from "@iconify/react";
import React from "react";
import {cnBase} from "tailwind-variants";

export function Controlled() {
  const [expandedKeys, setExpandedKeys] = React.useState(new Set<string | number>(["preview"]));
  const itemIds = ["preview", "download"]; // Track our disclosure items

  const {isNextDisabled, isPrevDisabled, onNext, onPrevious} = useDisclosureGroupNavigation({
    expandedKeys,
    itemIds,
    onExpandedChange: setExpandedKeys,
  });

  return (
    <div className="w-full max-w-md">
      <div className="rounded-panel flex flex-col gap-4 p-4">
        <div className="mb-2 flex items-center justify-between">
          <h3 className="text-lg font-semibold">HeroUI Native</h3>
          <div className="flex gap-2">
            <Button
              aria-label="Previous disclosure"
              isDisabled={isPrevDisabled}
              size="sm"
              variant="secondary"
              onPress={onPrevious}
            >
              <Icon className="size-4" icon="gravity-ui:chevron-up" />
            </Button>
            <Button
              aria-label="Next disclosure"
              isDisabled={isNextDisabled}
              size="sm"
              variant="secondary"
              onPress={onNext}
            >
              <Icon className="size-4" icon="gravity-ui:chevron-down" />
            </Button>
          </div>
        </div>
        <DisclosureGroup expandedKeys={expandedKeys} onExpandedChange={setExpandedKeys}>
          <Disclosure aria-label="Preview HeroUI Native" id="preview">
            <Disclosure.Heading>
              <Button
                slot="trigger"
                variant={expandedKeys.has("preview") ? "secondary" : "tertiary"}
                className={cnBase("w-full border-none", {
                  "bg-transparent": !expandedKeys.has("preview"),
                })}
              >
                <div className="flex w-full items-center justify-start gap-2">
                  <Icon icon="gravity-ui:qr-code" />
                  Preview HeroUI Native
                </div>
                <Disclosure.Indicator className="text-muted" />
              </Button>
            </Disclosure.Heading>
            <Disclosure.Content>
              <Disclosure.Body className="mx-2 flex flex-col items-center gap-2 p-4 text-center">
                <p className="text-muted text-sm">
                  Scan this QR code with your camera app to preview the HeroUI native components.
                </p>
                <img
                  alt="Expo Go QR Code"
                  className="max-w-54 aspect-square w-full object-cover"
                  src="https://raw.githubusercontent.com/heroui-inc/heroui-native/refs/heads/alpha/expo-go-qr.png"
                />
                <p className="text-muted text-sm">Expo must be installed on your device.</p>
                <Button className="mt-4" variant="primary">
                  <Icon className="[&_path]:fill-accent-foreground" icon="logos:expo-icon" />
                  Preview on Expo Go
                </Button>
              </Disclosure.Body>
            </Disclosure.Content>
          </Disclosure>
          <Separator className="my-2" />
          <Disclosure id="download">
            <Disclosure.Heading aria-label="Download HeroUI Native">
              <Button
                slot="trigger"
                variant={expandedKeys.has("download") ? "secondary" : "tertiary"}
                className={cnBase("w-full border-none", {
                  "bg-transparent": !expandedKeys.has("download"),
                })}
              >
                <div className="flex w-full items-center justify-start gap-2">
                  <Icon icon="tabler:brand-apple-filled" />
                  Download HeroUI Native
                </div>
                <Disclosure.Indicator className="text-muted" />
              </Button>
            </Disclosure.Heading>
            <Disclosure.Content>
              <Disclosure.Body className="mx-2 flex flex-col items-center gap-2 p-4 text-center">
                <p className="text-muted text-sm">
                  Scan this QR code with your camera app to preview the HeroUI native components.
                </p>
                <img
                  alt="Expo Go QR Code"
                  className="max-w-54 aspect-square w-full object-cover"
                  src="https://raw.githubusercontent.com/heroui-inc/heroui-native/refs/heads/alpha/expo-go-qr.png"
                />
                <p className="text-muted text-sm">Expo must be installed on your device.</p>
                <Button className="mt-4" variant="primary">
                  <Icon icon="tabler:brand-apple-filled" />
                  Download on App Store
                </Button>
              </Disclosure.Body>
            </Disclosure.Content>
          </Disclosure>
        </DisclosureGroup>
      </div>
    </div>
  );
}

Anatomy

Import all parts and piece them together.

import {DisclosureGroup, Disclosure} from '@heroui/react';

export default () => (
  <DisclosureGroup>
    <Disclosure id="item1">
      <Disclosure.Heading>
        <Disclosure.Trigger>
          <Disclosure.Indicator />
        </Disclosure.Trigger>
      </Disclosure.Heading>
      <Disclosure.Content />
    </Disclosure>
  </DisclosureGroup>
)

Styling

Passing Tailwind CSS classes

import {DisclosureGroup, Disclosure} from '@heroui/react';

function CustomDisclosureGroup() {
  return (
    <DisclosureGroup className="border rounded-lg p-4 space-y-2">
      <Disclosure id="first" className="border-b pb-2">
        <Disclosure.Trigger>Item 1</Disclosure.Trigger>
        <Disclosure.Content>Content 1</Disclosure.Content>
      </Disclosure>
      <Disclosure id="second">
        <Disclosure.Trigger>Item 2</Disclosure.Trigger>
        <Disclosure.Content>Content 2</Disclosure.Content>
      </Disclosure>
    </DisclosureGroup>
  );
}

Customizing the component classes

To customize the DisclosureGroup component classes, you can use the @layer components directive.
Learn more.

@layer components {
  .disclosure-group {
    @apply w-full;

    /* Performance optimization */
    contain: layout style;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The DisclosureGroup component uses these CSS classes (View source styles):

Base Classes

  • .disclosure-group - Base container styles with layout containment

Interactive States

The component supports both CSS pseudo-classes and data attributes for flexibility:

  • Disabled: :disabled or [aria-disabled="true"] on entire group
  • Expanded Management: Automatically manages [data-expanded] states on child Disclosure items

API Reference

DisclosureGroup Props

PropTypeDefaultDescription
expandedKeysSet<Key>-The currently expanded items (controlled)
defaultExpandedKeysIterable<Key>-The initially expanded items (uncontrolled)
onExpandedChange(keys: Set<Key>) => void-Handler called when expanded items change
allowsMultipleExpandedbooleanfalseWhether multiple items can be expanded simultaneously
isDisabledbooleanfalseWhether all disclosures in the group are disabled
childrenReactNode | RenderFunction-Disclosure items to render
classNamestring-Additional CSS classes

RenderProps

When using the render prop pattern, these values are provided:

PropTypeDescription
expandedKeysSet<Key>Currently expanded item keys
isDisabledbooleanWhether the group is disabled