Disclosure
Basic example
Disclosures are built using the Disclosure
, DisclosureButton
, and DisclosurePanel
components.
Clicking the DisclosureButton
will automatically open/close the DisclosurePanel
, and all components will receive the appropriate aria-*
attributes like aria-expanded
and aria-controls
.
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure>
<DisclosureButton>Is team pricing available?</DisclosureButton>
<DisclosurePanel>
Yes! You can purchase a license that you can share with your entire team.
</DisclosurePanel>
</Disclosure>
Styling
See here for some general notes on styling the components in this library.
Open panels
Disclosure
and its related components expose a slot prop containing the open
state of the panel. You can use this to apply whatever styles you wish.
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
import { ChevronRightIcon } from "@rgossiaux/svelte-heroicons/solid";
</script>
<Disclosure let:open>
<DisclosureButton>
<span>Is team pricing available?</span>
<!-- Use the `open` slot prop to rotate the icon when the panel is open -->
<ChevronRightIcon style={open ? "transform: rotate(90deg);" : ""} />
</DisclosureButton>
<DisclosurePanel>
Yes! You can purchase a license that you can share with your entire team.
</DisclosurePanel>
</Disclosure>
Showing/hiding the panel
By default, your DisclosurePanel
will be shown/hidden automatically based on the internal open state tracked within the Disclosure
component itself.
If you’d rather handle this yourself (perhaps because you need to add an extra wrapper element for one reason or another), you can add a static
prop to the DisclosurePanel
component to tell it to always render, and use the open
slot prop to show or hide the panel yourself.
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure let:open>
<DisclosureButton>Is team pricing available?</DisclosureButton>
{#if open}
<div>
<!-- Using `static`, `DisclosurePanel` is always rendered,
and ignores the `open` state -->
<DisclosurePanel static>
Yes! You can purchase a license that you can share with your entire
team.
</DisclosurePanel>
</div>
{/if}
</Disclosure>
Closing disclosures manually
To close a disclosure manually when clicking a child of its panel, render that child as a DisclosureButton
. You can use the as
prop to customize which element is being rendered.
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure>
<DisclosureButton>Open mobile menu</DisclosureButton>
<DisclosurePanel>
<DisclosureButton as="a" href="/home">Home</DisclosureButton>
<!-- ... -->
</DisclosurePanel>
</Disclosure>
This is especially useful when using disclosures for things like mobile menus that contain links, where you want the disclosure to close when navigating to the next page.
Alternatively, Disclosure
and DisclosurePanel
expose a close()
slot prop which you can use to imperatively close the panel:
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure>
<DisclosureButton>Solutions</DisclosureButton>
<DisclosurePanel let:close>
<button
on:click={async () => {
await fetch("/accept-terms", { method: "POST" });
close();
}}
>
Read and accept
</button>
<!-- ... -->
</DisclosurePanel>
</Disclosure>
By default the DisclosureButton
receives focus after calling close()
, but you can change this by passing an element into close(el)
.
Transitions
To animate the opening and closing of the disclosure panel, you can use this library’s Transition component or Svelte’s built-in transition engine. See that page for a comparison.
Using the Transition
component
To use the Transition
component, all you need to do is wrap the DisclosurePanel
in a <Transition>
and the panel will transition automatically.
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
Transition,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure>
<DisclosureButton>Is team pricing available?</DisclosureButton>
<!-- This example uses Tailwind's transition classes -->
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<DisclosurePanel>
<!-- ... -->
</DisclosurePanel>
</Transition>
</Disclosure>
The components in this library communicate with each other, so the Transition will be managed automatically when the Listbox is opened/closed. If you require more control over this behavior, you may use a more explicit version:
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
Transition,
} from "@rgossiaux/svelte-headlessui";
</script>
<Disclosure let:open>
<DisclosureButton>Is team pricing available?</DisclosureButton>
<!-- This example uses Tailwind's transition classes -->
<Transition
show={open}
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<!-- When controlling the transition manually, make sure to use `static` -->
<DisclosurePanel static>
<!-- ... -->
</DisclosurePanel>
</Transition>
</Disclosure>
Using Svelte transitions
The last example above also provides a blueprint for using Svelte transitions:
<script>
import {
Disclosure,
DisclosureButton,
DisclosurePanel,
} from "@rgossiaux/svelte-headlessui";
import { fade } from "svelte/transition";
</script>
<Disclosure let:open>
<DisclosureButton>Is team pricing available?</DisclosureButton>
{#if open}
<div transition:fade>
<!-- When controlling the transition manually, make sure to use `static` -->
<DisclosurePanel static>
<!-- ... -->
</DisclosurePanel>
</div>
{/if}
</Disclosure>
Make sure to use the static
prop, or else the exit transitions won’t work correctly.
Accessibility notes
Mouse interaction
Clicking a DisclosureButton
toggles the disclosure’s panel open and closed.
Keyboard interaction
Command | Description |
---|---|
<Enter> / <Space> when a DisclosureButton is focused |
Toggles panel |
Other
All relevant ARIA attributes are automatically managed.
For a full reference on all accessibility features implemented in Disclosure
, see the ARIA spec on Disclosure.
Component API
Disclosure
The main disclosure component.
Prop | Default | Type | Description |
---|---|---|---|
as |
div |
string |
The element the Disclosure should render as |
defaultOpen |
false |
boolean |
Whether the Disclosure should be open by default |
Slot prop | Type | Description |
---|---|---|
open |
boolean |
Whether the disclosure is open |
close |
(el?: HTMLElement) => void |
Closes the disclosure and focuses el , if passed, or the DisclosureButton if not |
DisclosureButton
This is the trigger button to toggle a disclosure.
You can also use this DisclosureButton
component inside a DisclosurePanel
. If you do, it will behave as a close button and have the appropriate aria-*
attributes.
Prop | Default | Type | Description |
---|---|---|---|
as |
button |
string |
The element the DisclosureButton should render as |
Slot prop | Type | Description |
---|---|---|
open |
boolean |
Whether or not the disclosure is open |
DisclosurePanel
This component contains the contents of your disclosure.
Prop | Default | Type | Description |
---|---|---|---|
as |
div |
string |
The element the DisclosurePanel should render as |
static |
false |
boolean |
Whether the element should ignore the internally managed open/closed state |
unmount |
true |
boolean |
Whether the element should be unmounted, instead of just hidden, based on the open/closed state |
Note that static
and unmount
cannot be used together.
Slot prop | Type | Description |
---|---|---|
open |
boolean |
Whether or not the disclosure is open |
close |
(el?: HTMLElement) => void |
Closes the disclosure and focuses el , if passed, or the DisclosureButton if not |