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.