# Accordion

Import: `import { Accordion } from '@neo4j-ndl/react'`

## Props

### Accordion

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` | ✅ |  | The content to display inside the accordion. Should only be `<Accordion.Item>` or `<Accordion.CleanItem>`. |
| `expandedItemId` | `AccordionItemId \| null` | ✅ |  | The id of the expanded accordion item. Only applicable if `isMultiple` is `false`. |
| `expandedItemIds` | `T[]` | ✅ |  | The ids of the expanded accordion items. Only applicable if `isMultiple` is `true`. |
| `isMultiple` | `boolean \| undefined` | ✅ |  | Whether multiple accordion items can be open at the same time. |
| `onChange` | `((expandedItemIds: T[]) => void) \| ((expandedItemId: T \| null) => void)` | ✅ |  | Callback function on component item expand/collapse change. |
| `ref` | `any` |  |  | A ref to apply to the root element. |

Where `T` is of the type `string | number | undefined`.

### Accordion.CleanItem

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `arrowPosition` | `'leading' \| 'trailing'` |  | `leading` | The position of the arrow. |
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  |  |
| `headingLevel` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` |  | `2` | The heading level for the accordion item title (1–6). Defaults to 2. |
| `isDisabled` | `boolean` |  | `false` | Whether the accordion item is disabled. |
| `itemId` | `AccordionItemId` | ✅ |  | The id of the accordion item. |
| `onExpandedChange` | `(expanded: boolean) => void` |  |  | Callback function on accordion item expand/collapse change. |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `title` | `string` | ✅ |  | The title of the accordion item. |
| `titleTypographyVariant` | `'body-large' \| 'body-medium' \| 'body-small' \| 'code' \| 'display' \| 'label' \| 'subheading-large' \| 'subheading-medium' \| 'subheading-small' \| 'title-1' \| 'title-2' \| 'title-3' \| 'title-4'` |  | `subheading-medium` | The typography variant for the title. |
| `trailingContent` | `ReactNode` |  |  | The content to display on the trailing side of accordion item. |

Where `T` is of the type `string | number | undefined`.

### Accordion.Item

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `arrowPosition` | `'leading' \| 'trailing'` |  | `leading` | The position of the arrow. |
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  |  |
| `headingLevel` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` |  | `2` | The heading level for the accordion item title (1–6). Defaults to 2. |
| `isDisabled` | `boolean` |  | `false` | Whether the accordion item is disabled. |
| `itemId` | `AccordionItemId` | ✅ |  | The id of the accordion item. |
| `onExpandedChange` | `(expanded: boolean) => void` |  |  | Callback function on accordion item expand/collapse change. |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `title` | `string` | ✅ |  | The title of the accordion item. |

Where `T` is of the type `string | number | undefined`.

`TypographyVariants` is of the type `'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'subheading-large' | 'subheading-medium' | 'subheading-small' | 'body-large' | 'body-medium' | 'body-small' | 'code' | 'label'`.

## Accessibility

## Implementation guidelines

Each accordion item is a tabbable element. You can also use the arrow keys to navigate through the accordion items. `Space` or `Enter` can be used to expand or collapse the accordion item. Interactive elements within expanded accordion items integrate into the tab order automatically.
Be sure to align the heading level of the accordion item title with the heading structure of the page.

## Examples

### Clean Items Expanded

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<
  typeof Accordion.CleanItem
>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemId, setExpandedItemId] = useState<AccordionItemId | null>(
    null,
  );

  const onChange = (expandedItemId: AccordionItemId | null) =>
    setExpandedItemId(expandedItemId);

  return (
    <Accordion
      expandedItemId={expandedItemId}
      isMultiple={false}
      onChange={onChange}
    >
      <Accordion.CleanItem
        itemId={itemIds[0]}
        title={`Accordion ${itemIds[0]}`}
      >
        {itemIds[0]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[1]}
        title={`Accordion ${itemIds[1]}`}
      >
        {itemIds[1]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[2]}
        title={`Accordion ${itemIds[2]}`}
      >
        {itemIds[2]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[3]}
        title={`Accordion ${itemIds[3]}`}
      >
        {itemIds[3]}
      </Accordion.CleanItem>
    </Accordion>
  );
};

export default Component;
```

### Default Expanded

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<typeof Accordion.Item>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemId, setExpandedItemId] = useState<AccordionItemId | null>(
    undefined,
  );

  const onChange = (expandedItemId: AccordionItemId | null) =>
    setExpandedItemId(expandedItemId);

  return (
    <Accordion
      expandedItemId={expandedItemId}
      isMultiple={undefined}
      onChange={onChange}
    >
      <Accordion.Item itemId={itemIds[0]} title={`Accordion ${itemIds[0]}`}>
        {itemIds[0]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[1]} title={`Accordion ${itemIds[1]}`}>
        {itemIds[1]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[2]} title={`Accordion ${itemIds[2]}`}>
        {itemIds[2]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[3]} title={`Accordion ${itemIds[3]}`}>
        {itemIds[3]}
      </Accordion.Item>
    </Accordion>
  );
};

export default Component;
```

### Full

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion, Checkbox } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<
  typeof Accordion.CleanItem
>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemIds, setExpandedItemIds] = useState<AccordionItemId[]>([
    itemIds[1],
  ]);

  const onChange = (expandedItemIds: AccordionItemId[]) =>
    setExpandedItemIds(expandedItemIds);

  const onExpandedChange = (hasExpanded: boolean) =>
    console.info(`Expanded change: ${hasExpanded}`);

  return (
    <Accordion
      expandedItemIds={expandedItemIds}
      isMultiple={true}
      onChange={onChange}
    >
      <Accordion.CleanItem
        itemId={itemIds[0]}
        title={`Accordion ${itemIds[0]}`}
      >
        {itemIds[0]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        arrowPosition="trailing"
        isDisabled={false}
        itemId={itemIds[1]}
        onExpandedChange={onExpandedChange}
        trailingContent={<Checkbox label="Right content" />}
        title={`Accordion ${itemIds[1]}`}
        titleTypographyVariant="title-4"
      >
        {itemIds[1]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[2]}
        title={`Accordion ${itemIds[2]}`}
      >
        {itemIds[2]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[3]}
        title={`Accordion ${itemIds[3]}`}
      >
        {itemIds[3]}
      </Accordion.CleanItem>
    </Accordion>
  );
};

export default Component;
```

### Multiple Expanded

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<typeof Accordion.Item>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemIds, setExpandedItemIds] = useState<AccordionItemId[]>([
    itemIds[0],
    itemIds[2],
  ]);

  const onChange = (expandedItemIds: AccordionItemId[]) =>
    setExpandedItemIds(expandedItemIds);

  return (
    <Accordion
      expandedItemIds={expandedItemIds}
      isMultiple={true}
      onChange={onChange}
    >
      <Accordion.Item itemId={itemIds[0]} title={`Accordion ${itemIds[0]}`}>
        {itemIds[0]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[1]} title={`Accordion ${itemIds[1]}`}>
        {itemIds[1]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[2]} title={`Accordion ${itemIds[2]}`}>
        {itemIds[2]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[3]} title={`Accordion ${itemIds[3]}`}>
        {itemIds[3]}
      </Accordion.Item>
    </Accordion>
  );
};

export default Component;
```

### Right Content

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion, Checkbox } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<
  typeof Accordion.CleanItem
>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemId, setExpandedItemId] = useState<AccordionItemId | null>(
    undefined,
  );

  const onChange = (expandedItemId: AccordionItemId | null) =>
    setExpandedItemId(expandedItemId);

  return (
    <Accordion
      expandedItemId={expandedItemId}
      isMultiple={undefined}
      onChange={onChange}
    >
      <Accordion.CleanItem
        itemId={itemIds[0]}
        title={`Accordion ${itemIds[0]}`}
        trailingContent={<Checkbox label="Right content" />}
      >
        {itemIds[0]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[1]}
        title={`Accordion ${itemIds[1]}`}
      >
        {itemIds[1]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[2]}
        title={`Accordion ${itemIds[2]}`}
      >
        {itemIds[2]}
      </Accordion.CleanItem>
      <Accordion.CleanItem
        itemId={itemIds[3]}
        title={`Accordion ${itemIds[3]}`}
      >
        {itemIds[3]}
      </Accordion.CleanItem>
    </Accordion>
  );
};

export default Component;
```

### Single Expanded

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Accordion } from '@neo4j-ndl/react';
import { useState } from 'react';

type AccordionItemId = React.ComponentProps<typeof Accordion.Item>['itemId'];

const Component = () => {
  const itemIds = ['item-1', 'item-2', 'item-3', 'item-4'];

  const [expandedItemId, setExpandedItemId] = useState<AccordionItemId | null>(
    itemIds[1],
  );

  const onChange = (expandedItemId: AccordionItemId | null) =>
    setExpandedItemId(expandedItemId);

  return (
    <Accordion
      expandedItemId={expandedItemId}
      isMultiple={false}
      onChange={onChange}
    >
      <Accordion.Item itemId={itemIds[0]} title={`Accordion ${itemIds[0]}`}>
        {itemIds[0]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[1]} title={`Accordion ${itemIds[1]}`}>
        {itemIds[1]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[2]} title={`Accordion ${itemIds[2]}`}>
        {itemIds[2]}
      </Accordion.Item>
      <Accordion.Item itemId={itemIds[3]} title={`Accordion ${itemIds[3]}`}>
        {itemIds[3]}
      </Accordion.Item>
    </Accordion>
  );
};

export default Component;
```
