# Disclosure

Disclosure is a component that allows users to progressively reveal content that
is not essential to the primary objective of a given view.

## Design & usage guidelines

Disclosure is useful for revealing or hiding content that is not essential for
the user to view all at once. You may want to put content inside of a Disclosure
to:

* reduce distractions or avoid overwhelming the user
* hide non-critical controls or options in a form

Disclosure should only be used to contain content or controls that aren't
required for the user to complete the primary objective of a given view.

For example, if a user has to make a selection between two options to complete a
task, do not put the selection controls in a Disclosure. A better example of
using a Disclosure would be if there is an optional setting that a user may want
to change but is not required to.

## Content guidelines

* `title` should be informative and label the type of content grouped in the
  body of the Disclosure.
  * This can either be a string or a React component. If a React component is
    used (containing multiple children), it should be wrapped in a container
    element and not a `<Fragment>` to maintain correct UI styling.
    * Caveat: The container element should NOT be `<div>` as it would break the
      semantics of the `<summary>` element. Instead, use a `<span>` or `<p>`
      tag.
  * The elements passed as a `title` can be plain text, or HTML that can be used
    within a paragraph (AKA
    ["phrasing content"](https://developer.mozilla.org/en-US/docs/Web/HTML/Content_categories#phrasing_content))
    to ensure that the title is accessible and can be properly read by screen
    readers. A heading may also be used but will not be treated as a heading by
    assistive technologies.
* `children` should be actionable and clear. The contents of a Disclosure can
  be:
  * plain text
  * any React component (except [Page](../Page/Page.md) and
    [Table](../Table/Table.md))

## Accessibility

* Users should be able to use their keyboard and toggle the component's
  open/close state
* A single Heading element is permitted in `summary` elements, however, it might
  lose some accessibility benefits, since according to
  [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary#summaries_as_headings):
  > Warning: Because the `<summary>` element has a default role of button (which
  > strips all roles from child elements), this example will not work for users
  > of assistive technologies such as screen readers. The `<h4>` will have its
  > role removed and thus will not be treated as a heading for these users.
* Include aria-expanded attribute on the trigger to communicate to assistive
  technology
* Include aria-controls attribute ties on the trigger to the content it controls
  using the id of the collapsible container
* The trigger contains a downward-pointing-arrow to hint that it can be
  expanded. When the disclosure item is in an expanded state, this is rotated
  180 degrees to point upwards
* The icon will be given an `aria-hidden="true"` attribute to hide it from
  assistive technologies, as well as `focusable="false"` to address an
  inconsistency in IE and older versions of Edge

## Responsiveness

The Disclosure component should handle both click and touch, as well as keyboard
inputs. It should fill the width of its container and if the component is less
than 375px wide, the title will wrap and should not be truncated.


## Component customization

### UNSAFE\_ props (advanced usage)

General information for using `UNSAFE_` props can be found
[here](../customizing-components/customizing-components.md).

**Note**: Use of `UNSAFE_` props is **at your own risk** and should be
considered a **last resort**. Future Disclosure updates may lead to unintended
breakages.

Disclosure has multiple elements that can be targeted with classes or styles:

* `container`: The container element of the Disclosure
* `summary`: The clickable header area of the Disclosure
* `summaryWrap`: The inner content within the summary, containing the title and
  toggle arrow
* `title`: The title element of the Disclosure
* `icon`: The toggle arrow of the Disclosure
* `arrowIconWrapper`: The wrapper element for the toggle arrow
* `content`: The content inside the Disclosure

#### UNSAFE\_className (web)

Use `UNSAFE_className` to apply custom classes to the Disclosure. This can be
useful for applying styles via CSS Modules.

```tsx
// Disclosure.tsx
UNSAFE_className={{
  container: styles.customDisclosure,
  summary: styles.customSummary,
}}

// Disclosure.stories.css
.customDisclosure {
  border: 3px solid var(--color-interactive);
  border-radius: var(--radius-base);
}

.customSummary {
  padding: var(--space-base);
}
```

#### UNSAFE\_style (web)

The `UNSAFE_style` prop provides granular control over the Disclosure's
appearance through inline styles, allowing you to modify the dimensions and
colors independently.

```tsx
<Disclosure
  ...
  UNSAFE_style={{
    container: {
      border: "3px solid var(--color-interactive)",
      borderRadius: "var(--radius-base)",
    },
    title: {
      textStyle: {
        color: "var(--color-interactive--hover)",
      },
    },
    icon: {
      path: {
        fill: "var(--color-interactive--subtle)",
      },
    },
  }}
>
  ...
</Disclosure>
```


## Props

### Web

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode | ReactNode[]` | Yes | — | Child content that is manged by this component. |
| `title` | `string | ReactElement<unknown, string | JSXElementConstructor<any>> | ReactElement<unknown, string | JSXElementConstructor<any>>[]` | Yes | — | Title for the disclosure pane. If ReactElement[] is provided, it must be wrapped in a container element (not a Fragme... |
| `defaultOpen` | `boolean` | No | `false` | This sets the default open state of the disclosure. By default the disclosure is closed. For use when the component i... |
| `onToggle` | `(newOpened: boolean) => void` | No | — | Callback that is called when the disclosure is toggled. |
| `open` | `boolean` | No | — | Used to make the disclosure a Controlled Component. |
| `UNSAFE_className` | `{ container?: string; summary?: string; summaryWrap?: string; title?: { textStyle?: string; }; icon?: { svg?: string; path?: string; }; arrowIconWrapper?: string; content?: string; }` | No | `{}` | **Use at your own risk:** Custom classNames for specific elements. This should only be used as a **last resort**. Usi... |
| `UNSAFE_style` | `{ container?: CSSProperties; summary?: CSSProperties; summaryWrap?: CSSProperties; title?: { textStyle?: CSSProperties; }; icon?: { ...; }; arrowIconWrapper?: CSSProperties; content?: CSSProperties; }` | No | `{}` | **Use at your own risk:** Custom style for specific elements. This should only be used as a **last resort**. Using th... |
