309 lines
10 KiB
Plaintext
309 lines
10 KiB
Plaintext
# Disclosure
|
|
|
|
<script>
|
|
import Preview from "./_Preview.svelte";
|
|
</script>
|
|
|
|
<Preview url="examples/disclosure" code="" class="h-[370px] bg-fuchsia-300"/>
|
|
|
|
## 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`.
|
|
|
|
```svelte
|
|
<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](general-concepts#component-styling) 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.
|
|
|
|
```svelte
|
|
<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.
|
|
|
|
```svelte
|
|
<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.
|
|
|
|
```svelte
|
|
<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:
|
|
|
|
```svelte
|
|
<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](/docs/latest/transition) 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.
|
|
|
|
```svelte
|
|
<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:
|
|
|
|
```svelte
|
|
<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:
|
|
|
|
```svelte
|
|
<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 <a href="https://www.w3.org/TR/wai-aria-practices-1.2/#Disclosure">the ARIA spec on Disclosure</a>.
|
|
|
|
## 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 |
|