Skip to content
LuoForge/Tungsten
Components/Disclosure·

Disclosure

since v4.3.0

Headless single-section disclosure primitive. Owns open/closed state and

a11y wiring (aria-expanded, aria-controls, hidden); the consumer

styles the trigger and panel however they like. The panel is always mounted

(just hidden when closed) so form state inside survives toggle cycles.

For multi-section collapsible groups, use {@link Accordion } instead.

Install

Add the package and import the component.

pnpm add @hey-mike/tungsten
pnpm add @hey-mike/tungsten
import { Disclosure } from '@hey-mike/tungsten';
import { Disclosure } from '@hey-mike/tungsten';

Preview

Same fixtures used by the visual-regression suite.

Usage

apps/docs/app/snapshots/disclosure/page.tsx

import { Disclosure, DisclosureTrigger, DisclosurePanel } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';

function Closed() {
  return (
    <Disclosure>
      <DisclosureTrigger>What is Tungsten?</DisclosureTrigger>
      <DisclosurePanel>A component library for LuoForge products.</DisclosurePanel>
    </Disclosure>
  );
}

function Open() {
  return (
    <Disclosure defaultOpen>
      <DisclosureTrigger>What is Tungsten?</DisclosureTrigger>
      <DisclosurePanel>A component library for LuoForge products.</DisclosurePanel>
    </Disclosure>
  );
}

function MultipleItems() {
  return (
    <div className="flex w-64 flex-col gap-2">
      <Disclosure defaultOpen>
        <DisclosureTrigger>First item (open)</DisclosureTrigger>
        <DisclosurePanel>Content for the first item.</DisclosurePanel>
      </Disclosure>
      <Disclosure>
        <DisclosureTrigger>Second item (closed)</DisclosureTrigger>
        <DisclosurePanel>Content for the second item.</DisclosurePanel>
      </Disclosure>
      <Disclosure>
        <DisclosureTrigger>Third item (closed)</DisclosureTrigger>
        <DisclosurePanel>Content for the third item.</DisclosurePanel>
      </Disclosure>
    </div>
  );
}

export default function DisclosureSnapshot() {
  return (
    <VariantGrid
      title="Disclosure"
      variants={[
        { label: 'closed', node: <Closed /> },
        { label: 'open', node: <Open /> },
        { label: 'multiple', node: <MultipleItems /> },
      ]}
    />
  );
}
import { Disclosure, DisclosureTrigger, DisclosurePanel } from '@hey-mike/tungsten';
import { VariantGrid } from '../_components/VariantGrid';

function Closed() {
  return (
    <Disclosure>
      <DisclosureTrigger>What is Tungsten?</DisclosureTrigger>
      <DisclosurePanel>A component library for LuoForge products.</DisclosurePanel>
    </Disclosure>
  );
}

function Open() {
  return (
    <Disclosure defaultOpen>
      <DisclosureTrigger>What is Tungsten?</DisclosureTrigger>
      <DisclosurePanel>A component library for LuoForge products.</DisclosurePanel>
    </Disclosure>
  );
}

function MultipleItems() {
  return (
    <div className="flex w-64 flex-col gap-2">
      <Disclosure defaultOpen>
        <DisclosureTrigger>First item (open)</DisclosureTrigger>
        <DisclosurePanel>Content for the first item.</DisclosurePanel>
      </Disclosure>
      <Disclosure>
        <DisclosureTrigger>Second item (closed)</DisclosureTrigger>
        <DisclosurePanel>Content for the second item.</DisclosurePanel>
      </Disclosure>
      <Disclosure>
        <DisclosureTrigger>Third item (closed)</DisclosureTrigger>
        <DisclosurePanel>Content for the third item.</DisclosurePanel>
      </Disclosure>
    </div>
  );
}

export default function DisclosureSnapshot() {
  return (
    <VariantGrid
      title="Disclosure"
      variants={[
        { label: 'closed', node: <Closed /> },
        { label: 'open', node: <Open /> },
        { label: 'multiple', node: <MultipleItems /> },
      ]}
    />
  );
}

Props

Surface specific to <Disclosure />.

PropTypeDefaultDescription
openbooleanControlled open state.
onOpenChange((open: boolean) => void) | ((open: boolean) => void)Fires with the next open state. Required alongside open. Optional change callback in uncontrolled mode (e.g. analytics). State is still owned internally.
defaultOpenbooleanInitial open state in uncontrolled mode. Ignored when open is provided.

Sub-components

Composition slots re-exported from the same module.

DisclosureTrigger

PropTypeDefaultDescription
asChildbooleanWhen true, merge props onto the single React child instead of rendering a <button>.

DisclosurePanel

No library-specific props. Pass through standard HTML attributes for the underlying element.

Source