useDisclosure
Provides the behavior and accessibility implementation for a disclosure component.
| install | yarn add @react-aria/disclosure |
|---|---|
| version | 3.0.0-alpha.0 |
| usage | import {useDisclosure} from '@react-aria/disclosure' |
API#
useDisclosure(
props: AriaDisclosureProps,
state: DisclosureState,
ref?: RefObject<Element
| | null>
): DisclosureAria
Features#
A disclosure is a collapsible section of content. It is composed of a trigger button and a panel that contains the content. useDisclosure can be used to implement these in an accessible way.
- Support for mouse, touch, and keyboard interactions to open and close the disclosure
- Support for disabled disclosures
- Follows the disclosure ARIA pattern, semantically linking the trigger button and panel
- Uses hidden="until-found" in supported browsers, enabling find-in-page search support and improved search engine visibility for collapsed content
Anatomy#
A disclosure consists of a trigger button and a panel. Clicking on or pressing Enter or Space while the trigger button is focused toggles the visibility of the panel.
useDisclosure returns props to spread onto the trigger button and panel.
| Name | Type | Description |
buttonProps | AriaButtonProps | Props for the disclosure button. |
panelProps | HTMLAttributes<HTMLElement> | Props for the disclosure panel. |
State is managed by the useDisclosureState
hook in @react-stately/disclosure. The state object should be passed as an option to useDisclosure.
Example#
This example displays a basic disclosure with a button that toggles the visibility of the panel.
import {useDisclosureState} from '@react-stately/disclosure';
import {useDisclosure} from '@react-aria/disclosure';
import {useButton} from '@react-aria/button';
function Disclosure(props) {
let state = useDisclosureState(props);
let panelRef = React.useRef<HTMLDivElement | null>(null);
let triggerRef = React.useRef<HTMLButtonElement | null>(null);
let { buttonProps: triggerProps, panelProps } = useDisclosure(
props,
state,
panelRef
);
let { buttonProps } = useButton(triggerProps, triggerRef);
return (
<div className="disclosure">
<h3>
<button className="trigger" ref={triggerRef} {...buttonProps}>
<svg viewBox="0 0 24 24">
<path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
</svg>
{props.title}
</button>
</h3>
<div className="panel" ref={panelRef} {...panelProps}>
<p>
{props.children}
</p>
</div>
</div>
);
}
<Disclosure title="System Requirements">
Details about system requirements here.
</Disclosure>
import {useDisclosureState} from '@react-stately/disclosure';
import {useDisclosure} from '@react-aria/disclosure';
import {useButton} from '@react-aria/button';
function Disclosure(props) {
let state = useDisclosureState(props);
let panelRef = React.useRef<HTMLDivElement | null>(null);
let triggerRef = React.useRef<HTMLButtonElement | null>(
null
);
let { buttonProps: triggerProps, panelProps } =
useDisclosure(props, state, panelRef);
let { buttonProps } = useButton(triggerProps, triggerRef);
return (
<div className="disclosure">
<h3>
<button
className="trigger"
ref={triggerRef}
{...buttonProps}
>
<svg viewBox="0 0 24 24">
<path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
</svg>
{props.title}
</button>
</h3>
<div className="panel" ref={panelRef} {...panelProps}>
<p>
{props.children}
</p>
</div>
</div>
);
}
<Disclosure title="System Requirements">
Details about system requirements here.
</Disclosure>
import {useDisclosureState} from '@react-stately/disclosure';
import {useDisclosure} from '@react-aria/disclosure';
import {useButton} from '@react-aria/button';
function Disclosure(
props
) {
let state =
useDisclosureState(
props
);
let panelRef = React
.useRef<
| HTMLDivElement
| null
>(null);
let triggerRef = React
.useRef<
| HTMLButtonElement
| null
>(null);
let {
buttonProps:
triggerProps,
panelProps
} = useDisclosure(
props,
state,
panelRef
);
let { buttonProps } =
useButton(
triggerProps,
triggerRef
);
return (
<div className="disclosure">
<h3>
<button
className="trigger"
ref={triggerRef}
{...buttonProps}
>
<svg viewBox="0 0 24 24">
<path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
</svg>
{props.title}
</button>
</h3>
<div
className="panel"
ref={panelRef}
{...panelProps}
>
<p>
{props
.children}
</p>
</div>
</div>
);
}
<Disclosure title="System Requirements">
Details about system
requirements here.
</Disclosure>
Show CSS
.disclosure {
.trigger {
background: none;
border: none;
box-shadow: none;
font-weight: bold;
font-size: 16px;
display: flex;
align-items: center;
gap: 8px;
svg {
rotate: 0deg;
transition: rotate 200ms;
width: 12px;
height: 12px;
fill: none;
stroke: currentColor;
stroke-width: 3px;
}
&[aria-expanded="true"] svg {
rotate: 90deg;
}
}
}
.panel {
margin-left: 32px;
}.disclosure {
.trigger {
background: none;
border: none;
box-shadow: none;
font-weight: bold;
font-size: 16px;
display: flex;
align-items: center;
gap: 8px;
svg {
rotate: 0deg;
transition: rotate 200ms;
width: 12px;
height: 12px;
fill: none;
stroke: currentColor;
stroke-width: 3px;
}
&[aria-expanded="true"] svg {
rotate: 90deg;
}
}
}
.panel {
margin-left: 32px;
}.disclosure {
.trigger {
background: none;
border: none;
box-shadow: none;
font-weight: bold;
font-size: 16px;
display: flex;
align-items: center;
gap: 8px;
svg {
rotate: 0deg;
transition: rotate 200ms;
width: 12px;
height: 12px;
fill: none;
stroke: currentColor;
stroke-width: 3px;
}
&[aria-expanded="true"] svg {
rotate: 90deg;
}
}
}
.panel {
margin-left: 32px;
}Usage#
The following examples show how to use the Disclosure component created in the above example.
Default expansion#
Whether or not the disclosure is expanded or not by default can be set with the defaultExpanded prop.
<Disclosure title="System Requirements" defaultExpanded>
Details about system requirements here.
</Disclosure>
<Disclosure title="System Requirements" defaultExpanded>
Details about system requirements here.
</Disclosure>
<Disclosure
title="System Requirements"
defaultExpanded
>
Details about system
requirements here.
</Disclosure>
Controlled expansion#
Expansion can be controlled using the isExpanded prop, paired with the onExpandedChange event. The onExpandedChange event is fired when the user presses the trigger button.
function ControlledDisclosure(props) {
let [isExpanded, setExpanded] = React.useState(false);
return (
<Disclosure
title="System Requirements"
isExpanded={isExpanded}
onExpandedChange={setExpanded}
>
Details about system requirements here.
</Disclosure>
);
}
function ControlledDisclosure(props) {
let [isExpanded, setExpanded] = React.useState(false);
return (
<Disclosure
title="System Requirements"
isExpanded={isExpanded}
onExpandedChange={setExpanded}
>
Details about system requirements here.
</Disclosure>
);
}
function ControlledDisclosure(
props
) {
let [
isExpanded,
setExpanded
] = React.useState(
false
);
return (
<Disclosure
title="System Requirements"
isExpanded={isExpanded}
onExpandedChange={setExpanded}
>
Details about
system requirements
here.
</Disclosure>
);
}
Disabled#
A disclosure can be disabled with the isDisabled prop. This will disable the trigger button and prevent the panel from being opened or closed.
<Disclosure title="System Requirements" isDisabled>
Details about system requirements here.
</Disclosure>
<Disclosure title="System Requirements" isDisabled>
Details about system requirements here.
</Disclosure>
<Disclosure
title="System Requirements"
isDisabled
>
Details about system
requirements here.
</Disclosure>
Disclosure Group (Accordion)#
See the docs for useDisclosureGroupState in react-stately for an example of a disclosure group.