Skip to content


A disclosure is a button that controls the visibility of a panel of content. When the content inside the panel is hidden, it is often styled as a typical push button with a right-pointing arrow or triangle to hint that activating the button will display additional content. When the content is visible, the arrow or triangle typically points down.

If you have a group of disclosures that stack vertically and exist within the same logical context, you may want to use @reach/accordion instead.


From the command line in your project directory, run npm install @reach/disclosure or yarn add @reach/disclosure. Then import the components that you need:

npm install @reach/disclosure# oryarn add @reach/disclosure
import {  Disclosure,  DisclosureButton,  DisclosurePanel,} from "@reach/disclosure";


function Example() {  return (    <Disclosure>      <DisclosureButton>Find out what lies beneath</DisclosureButton>      <DisclosurePanel>Here I am! I am the buried treasure!</DisclosurePanel>    </Disclosure>  );}

Component API


The wrapper component and context provider for a disclosure's button and panel components. A disclosure should never have more than one button or panel descendants.

<Disclosure>  <DisclosureButton>Do a thing</DisclosureButton>  <DisclosurePanel>...</DisclosurePanel></Disclosure>

It is important to note that the Disclosure component doesn't actually render a DOM node, so there is no way to add styles to a disclosure wrapper directly. If you want your disclosure to have a wrapper element you can nest one directly.

<Disclosure>  <div style={{ padding: 10 }}>    <DisclosureButton>Do a thing</DisclosureButton>    <DisclosurePanel>...</DisclosurePanel>  </div></Disclosure>

Controlled Disclosure

If you want to control the disclosure's value, you can do so by passing open and onChange props.

const [isOpen, setOpen] = useState(false);return (  <Disclosure open={isOpen} onChange={() => setOpen(!isOpen)}>    <DisclosureButton />    <DisclosurePanel />  </Disclosure>);

Disclosure Props

idstring | numberfalse
Disclosure children

children: React.ReactNode

Disclosure expects to receive accept DisclosureButton and DisclosurePanel components as either direct children or descendants. It can also accept wrapper elements if desired, though it is not recommended to pass other arbitrary components within a disclosure in most cases.

<div>  {/* OK! */}  <Disclosure>    <DisclosureButton>Click Me</DisclosureButton>    <DisclosurePanel>Collapse or open this content!</DisclosurePanel>  </Disclosure>  {/* Also OK! */}  <Disclosure>    <div>      <DisclosureButton>Click Me</DisclosureButton>      <DisclosurePanel>Collapse or open this content!</DisclosurePanel>    </div>  </Disclosure>  {/* Probably confusing, you should avoid! */}  <Disclosure>    <div>Mary had a little lamb, little lamb, blah blah blah</div>    <DisclosureButton>Click Me</DisclosureButton>    <DisclosurePanel>Collapse or open this content!</DisclosurePanel>    <blockquote>You miss 100% of the shots you don't take</blockquote>  </Disclosure></div>
Disclosure defaultOpen

defaultOpen?: boolean

Whether or not an uncontrolled disclosure component should default to its open state on the initial render. Defaults to false.

Disclosure id

id?: string | number

An id used to assign aria and id attributes to nested DisclosureButton and DisclosurePanel components.

Since the Disclosure component itself does not render a DOM element, an id prop will not appear in the DOM directly as may be expected. Rather, we need to generate IDs for the panel and button based on a disclosure ID for aria compliance. If no id is passed we will generate descendant IDs for you.

<Disclosure id="awesome-disclosure">  <div>    {" "}    {/* no ID passed here! */}    <DisclosureButton /> {/* <button id="awesome-disclosure--button" /> */}    <DisclosurePanel /> {/* <div id="awesome-disclosure--panel" /> */}  </div></Disclosure>
Disclosure onChange

onChange?: () => void

The callback that is fired when a disclosure's open state is changed.

Disclosure open

open?: boolean

The controlled open state of the disclosure. The open prop should be used along with onChange to create controlled disclosure components.

const [open, setOpen] = useState(false);return (  <Disclosure open={open} onChange={() => setOpen(!open)}>    <DisclosureButton>I have a secret</DisclosureButton>    <DisclosurePanel>      Ante rhoncus facilisis iaculis nostra faucibus vehicula ac consectetur      pretium, lacus nunc consequat id viverra facilisi ligula eleifend, congue      gravida malesuada proin scelerisque luctus est convallis.    </DisclosurePanel>  </Disclosure>);


The trigger button a user clicks to interact with a disclosure.

DisclosureButton CSS Selectors

Please see the styling guide.

[data-reach-disclosure-button] {}[data-reach-disclosure-button][data-state="open"] {}[data-reach-disclosure-button][data-state="collapsed"] {}

DisclosureButton Props

DisclosureButton children

children: React.ReactNode

Typically a text string that serves as a label for the disclosure button, though nested DOM nodes can be passed as well so long as they are valid children of interactive elements.


The collapsible panel in which inner content for a disclosure item is rendered.

DisclosurePanel CSS Selectors

Please see the styling guide.

[data-reach-disclosure-panel] {}[data-reach-disclosure-panel][data-state="open"] {}[data-reach-disclosure-panel][data-state="collapsed"] {}

DisclosurePanel Props

DisclosurePanel children

children: React.ReactNode

Inner collapsible content for the disclosure item.