Skip to content

Disclosure ​

A single expandable section — a button that shows or hides a panel of content. Use it for FAQs, collapsible details, "show more" sections, or to tuck away secondary information until it's needed. Built on Headless UI's disclosure, so the aria-expanded/aria-controls wiring, keyboard support, and focus are handled for you.

A disclosure is independent: each one manages its own open state. Stack several to form an FAQ or accordion-style list.

Anatomy ​

Disclosure ← the root; manages open/closed state
├── DisclosureButton ← the trigger row (shows a rotating chevron)
└── DisclosurePanel ← the collapsible content

The button's content is the heading; the panel's content is what's revealed. The chevron rotates automatically with the open state.

Usage ​

BasicA button that toggles a panel.
<script setup lang="ts">
import { Disclosure, DisclosureTrigger, DisclosureContent } from "@dlbcodes/ui";
</script>

<template>
    <div class="w-full max-w-md">
        <Disclosure>
            <DisclosureTrigger>Is team pricing available?</DisclosureTrigger>
            <DisclosureContent>
                Yes — you can buy a single license and share it with your whole
                team.
            </DisclosureContent>
        </Disclosure>
    </div>
</template>

Open by default ​

Set defaultOpen on the Disclosure to have it expanded initially.

Default openStarts expanded.
<script setup lang="ts">
import { Disclosure, DisclosureTrigger, DisclosureContent } from "@dlbcodes/ui";
</script>

<template>
    <div class="w-full max-w-md">
        <Disclosure :default-open="true">
            <DisclosureTrigger>Already expanded</DisclosureTrigger>
            <DisclosureContent>
                This panel starts open because <code>defaultOpen</code> is set.
            </DisclosureContent>
        </Disclosure>
    </div>
</template>

FAQ list ​

Stack disclosures to build an FAQ. Each is independent — opening one doesn't close the others.

FAQA stack of disclosures.
<script setup lang="ts">
import { Disclosure, DisclosureTrigger, DisclosureContent } from "@dlbcodes/ui";

const faqs = [
    {
        q: "Can I cancel anytime?",
        a: "Yes, you can cancel your subscription at any point from your account settings.",
    },
    {
        q: "Do you offer refunds?",
        a: "We offer a 30-day money-back guarantee on all annual plans.",
    },
    {
        q: "Is there a free trial?",
        a: "Every plan comes with a 14-day free trial — no card required.",
    },
];
</script>

<template>
    <div class="w-full max-w-md">
        <Disclosure v-for="faq in faqs" :key="faq.q">
            <DisclosureTrigger>{{ faq.q }}</DisclosureTrigger>
            <DisclosureContent>{{ faq.a }}</DisclosureContent>
        </Disclosure>
    </div>
</template>

Custom trigger ​

DisclosureButton exposes the open state via its default slot, so you can change the label or content based on whether the panel is open.

Custom triggerA label that reflects the open state.
<script setup lang="ts">
import { Disclosure, DisclosureTrigger, DisclosureContent } from "@dlbcodes/ui";
</script>

<template>
    <div class="w-full max-w-md">
        <Disclosure>
            <DisclosureTrigger>
                <template #default="{ open }">
                    {{ open ? "Hide details" : "Show details" }}
                </template>
            </DisclosureTrigger>
            <DisclosureContent>
                The button label changes based on the open state, via the
                <code>open</code> slot prop.
            </DisclosureContent>
        </Disclosure>
    </div>
</template>

Props ​

Disclosure ​

PropTypeDefaultDescription
defaultOpenbooleanfalseWhether the panel is expanded initially.
classstring—Classes merged onto the root.

Exposes open (boolean) via its default slot.

DisclosureButton ​

Takes only class. Its slot content is the trigger label, and it exposes open (boolean) via the default slot. A chevron is included automatically and rotates with the open state.

DisclosurePanel ​

Takes only class. Its slot content is the collapsible body.

Accessibility ​

  • Built on Headless UI's disclosure, so the button gets aria-expanded and aria-controls, and the panel is associated with the button via generated ids.
  • The button is a real, focusable <button>; Enter/Space toggle the panel.
  • Each disclosure is independent — for a true single-open accordion (opening one closes the others), you'd coordinate their state yourself.