# Collapsible Card
> Component for collapsing and expanding sections of related content one at a time with card-like look.

## Import

```js
import { CollapsibleCard } from '@gemini-suite/vera-react';
```

CollapsibleCard is a compound component that consists of multiple parts:

- `CollapsibleCard.Root`: The wrapper that contains all the parts of a component and provides context for its children.
- `CollapsibleCard.Header`: The header of the card which acts as a trigger to expand or collapse the card content.
- `CollapsibleCard.Body`: The container for the collapsible card main content.
- `CollapsibleCard.Footer`: The footer at the bottom of the collapsible content. Typically used to house card actions.

## Examples

### Basic

`CollapsibleCard` helps showing pieces of content as needed while keeping the interface organized and visually manageable.

<Callout variant="tip">

`CollapsibleCard` internally uses [Collapsible](/components/collapsible) and [Card](/components/card) components, sharing the same behaviors and animation.

</Callout>

```jsx
<CollapsibleCard.Root>
  <CollapsibleCard.Header>{'Header'}</CollapsibleCard.Header>
  <CollapsibleCard.Body>
    <Flex flow="column">
      <FakeText words="50,60" />
      <FakeText words="50,60" />
    </Flex>
  </CollapsibleCard.Body>
</CollapsibleCard.Root>
```

### Controlled

You can easily make the `CollapsibleCard` controlled, by passing your own state to `isOpen` prop.
`onIsOpenChange` handler is called when the state of the collapsible card changes, allowing you to sync state.

```jsx
() => {
  const [state, setState] = React.useState(true);

  return (
    <CollapsibleCard.Root isOpen={state} onIsOpenChange={setState}>
      <CollapsibleCard.Header>{'Controlled state'}</CollapsibleCard.Header>
      <CollapsibleCard.Body>
        <FakeText words="50" />
      </CollapsibleCard.Body>
    </CollapsibleCard.Root>
  );
};
```

### With footer

As with regular [Card component](/components/card), you can add `CollapsibleCard.Footer` alongside the `CollapsibleCard.Body`.

```jsx
<CollapsibleCard.Root defaultIsOpen>
  <CollapsibleCard.Header>{'Header'}</CollapsibleCard.Header>
  <CollapsibleCard.Body>
    <FakeText words="35" />
  </CollapsibleCard.Body>
  <CollapsibleCard.Footer as={Link} isExternal>
    {'Text link'}
  </CollapsibleCard.Footer>
</CollapsibleCard.Root>
```

### Sizes

`CollapsibleCard` supports two sizes: `medium` (default) and `small`. Use the `size` prop to control the size.

```jsx
<Flex flow="column">
  <Box css={{ maxWidth: 400 }}>
    <CollapsibleCard.Root size="medium">
      <CollapsibleCard.Header>{'Medium (default)'}</CollapsibleCard.Header>
      <CollapsibleCard.Body>
        <FakeText words="50,60" />
      </CollapsibleCard.Body>
      <CollapsibleCard.Footer as={Link} isExternal>
        {'Text link'}
      </CollapsibleCard.Footer>
    </CollapsibleCard.Root>
  </Box>
  <Box css={{ maxWidth: 300 }}>
    <CollapsibleCard.Root size="small">
      <CollapsibleCard.Header>{'Small'}</CollapsibleCard.Header>
      <CollapsibleCard.Body>
        <FakeText words="50,60" />
      </CollapsibleCard.Body>
      <CollapsibleCard.Footer as={Link} isExternal>
        {'Text link'}
      </CollapsibleCard.Footer>
    </CollapsibleCard.Root>
  </Box>
</Flex>
```

### Unmount on exit

Similar to [Collapsible component](/components/collapsible), you can force `<CollapsibleCard.Body>` children to unmount when exit state is done by setting `unmountOnExit` to `true`.

```jsx
<CollapsibleCard.Root
  unmountOnExit
  onExitComplete={() => {
    console.log('content unmounted');
  }}
>
  <CollapsibleCard.Header>{'Header'}</CollapsibleCard.Header>
  <CollapsibleCard.Body>
    {'Content that will unmount when exit animation is done.'}
  </CollapsibleCard.Body>
</CollapsibleCard.Root>
```

### Complex content

`CollapsibleCard.Header` and `CollapsibleCard.Body` can contain any content, including other components. You can render any element within the trigger such as an icon or a label alongside the card title.

```jsx
<ContentBlock gutters="none" center={false}>
  <Flex flow="column">
    <Heading variant="gamma">Settings</Heading>
    <CollapsibleCard.Root>
      <CollapsibleCard.Header>
        <Flex cross="start" gap="spacingS">
          <FlexItem shrink={0} as={Flex} display="inline" gap="none">
            {'\u200b'}
            <SvgIcon iconName="bell" />
          </FlexItem>
          <FlexItem flex="auto">
            <Text as="div" fontWeight="semibold">
              {'Notifications'}
            </Text>
            <Text variant="zeta" color="foregroundNeutralSubtle">
              {'Toggle notification settings'}
            </Text>
          </FlexItem>
        </Flex>
      </CollapsibleCard.Header>
      <CollapsibleCard.Body>
        <ContentBlock center={false} gutters="none">
          <Flex flow="column">
            <Switch.Root defaultIsActive>
              <Switch.Label>{'Allow notifications?'}</Switch.Label>
              <Switch.Indicator>
                <Switch.On>{'Yes'}</Switch.On>
                <Switch.Off>{'No'}</Switch.Off>
              </Switch.Indicator>
            </Switch.Root>
            <FormField.Root as={Flex} flow="column">
              <FormField.Label size="small">{'Channels'}</FormField.Label>
              <CheckboxGroup defaultValue={['app', 'email']}>
                <Flex flow="column" gap="spacingXs">
                  <Checkbox.Root value="app">
                    <Checkbox.Indicator />
                    <Checkbox.Label>{'In application'}</Checkbox.Label>
                  </Checkbox.Root>
                  <Checkbox.Root value="email">
                    <Checkbox.Indicator />
                    <Checkbox.Label>{'Email'}</Checkbox.Label>
                  </Checkbox.Root>
                </Flex>
              </CheckboxGroup>
            </FormField.Root>
            <FormField.Root as={Flex} flow="column">
              <FormField.Label size="small">
                {'Email notifications frequency'}
              </FormField.Label>
              <RadioGroup defaultValue="instantly">
                <Flex flow="column" gap="spacingXs">
                  <Radio.Root value="instantly">
                    <Radio.Indicator />
                    <Flex flow="column" gap="none">
                      <Radio.Label>{'Instantly'}</Radio.Label>
                      <Radio.HelperText>
                        {'Send notifications as they happen'}
                      </Radio.HelperText>
                    </Flex>
                  </Radio.Root>
                  <Radio.Root value="hourly">
                    <Radio.Indicator />
                    <Flex flow="column" gap="none">
                      <Radio.Label>{'Hourly'}</Radio.Label>
                      <Radio.HelperText>
                        {'Send a summary once an hour'}
                      </Radio.HelperText>
                    </Flex>
                  </Radio.Root>
                  <Radio.Root value="daily">
                    <Radio.Indicator />
                    <Flex flow="column" gap="none">
                      <Radio.Label>{'Daily'}</Radio.Label>
                      <Radio.HelperText>
                        {'Send a summary once a day'}
                      </Radio.HelperText>
                    </Flex>
                  </Radio.Root>
                </Flex>
              </RadioGroup>
            </FormField.Root>
          </Flex>
        </ContentBlock>
      </CollapsibleCard.Body>
    </CollapsibleCard.Root>
    <CollapsibleCard.Root>
      <CollapsibleCard.Header>
        <Flex cross="start" gap="spacingS">
          <FlexItem shrink={0} as={Flex} display="inline" gap="none">
            {'\u200b'}
            <SvgIcon iconName="database" />
          </FlexItem>
          <FlexItem flex="auto">
            <Text as="div" fontWeight="semibold">
              {'Database'}
            </Text>
            <Text variant="zeta" color="foregroundNeutralSubtle">
              {'Edit database connection settings'}
            </Text>
          </FlexItem>
        </Flex>
      </CollapsibleCard.Header>
      <CollapsibleCard.Body>
        <ContentBlock center={false} gutters="none">
          <Flex flow="column">
            <FormField.Root as={Flex} flow="column">
              <FormField.Label>{'Server URL'}</FormField.Label>
              <TextInput type="url" placeholder="https://" />
            </FormField.Root>
            <FormField.Root as={Flex} flow="column">
              <FormField.Label>{'Database'}</FormField.Label>
              <TextInput />
            </FormField.Root>
            <FormField.Root as={Flex} flow="column">
              <FormField.Label>{'User name'}</FormField.Label>
              <TextInput />
            </FormField.Root>
            <FormField.Root as={Flex} flow="column">
              <FormField.Label>{'Password'}</FormField.Label>
              <TextInput type="password" />
            </FormField.Root>
            <Box>
              <Button>{'Test connection'}</Button>
            </Box>
          </Flex>
        </ContentBlock>
      </CollapsibleCard.Body>
    </CollapsibleCard.Root>
  </Flex>
</ContentBlock>
```

Often case is to display a short message that summarizes some complex/lengthy data in the card header and organize it in the body with [Data List](/components/data-list) or [Table](/components/tables/table) component.

```jsx
<ContentBlock gutters="none" center={false}>
  <Flex flow="column">
    <Heading variant="gamma">{'Event log'}</Heading>
    <Flex as="ul" paddingLeft="none" margin="none" flow="column" gap="spacingS">
      <CollapsibleCard.Root as="li">
        <CollapsibleCard.Header>
          <Flex gap="spacingS">
            <Label size="small" color="info">
              {'Info'}
            </Label>
            <Text>{'New timeseries received'}</Text>
          </Flex>
        </CollapsibleCard.Header>
        <CollapsibleCard.Body>
          <DataList.Root>
            <DataList.Row>
              <DataList.Label>{'Level'}</DataList.Label>
              <DataList.Value>
                <Label size="small" color="info">
                  {'Info'}
                </Label>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Date'}</DataList.Label>
              <DataList.Value>
                <time dateTime="2023-03-08T10:37:25.865Z">
                  {'08.03.2023 11:37:25'}
                </time>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Event ID'}</DataList.Label>
              <DataList.Value>{'lTh9aE'}</DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Message'}</DataList.Label>
              <DataList.Value>{'New timeseries received'}</DataList.Value>
            </DataList.Row>
          </DataList.Root>
        </CollapsibleCard.Body>
        <CollapsibleCard.Footer>
          <Button
            variant="outline"
            size="small"
            leftIcon={<SvgIcon iconName="copy" />}
          >
            {'Copy as JSON'}
          </Button>
        </CollapsibleCard.Footer>
      </CollapsibleCard.Root>
      <CollapsibleCard.Root as="li">
        <CollapsibleCard.Header>
          <Flex gap="spacingS">
            <Label size="small" color="success">
              {'Success'}
            </Label>
            <Text>{'Timeseries uploaded'}</Text>
          </Flex>
        </CollapsibleCard.Header>
        <CollapsibleCard.Body>
          <DataList.Root>
            <DataList.Row>
              <DataList.Label>{'Level'}</DataList.Label>
              <DataList.Value>
                <Label size="small" color="success">
                  {'Success'}
                </Label>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Date'}</DataList.Label>
              <DataList.Value>
                <time dateTime="2023-02-06T11:29:14.484Z">
                  {'06.02.2023 12:29:14'}
                </time>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Event ID'}</DataList.Label>
              <DataList.Value>{'Gwu5hW'}</DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Message'}</DataList.Label>
              <DataList.Value>{'Timeseries uploaded'}</DataList.Value>
            </DataList.Row>
          </DataList.Root>
        </CollapsibleCard.Body>
        <CollapsibleCard.Footer>
          <Button
            variant="outline"
            size="small"
            leftIcon={<SvgIcon iconName="copy" />}
          >
            {'Copy as JSON'}
          </Button>
        </CollapsibleCard.Footer>
      </CollapsibleCard.Root>
      <CollapsibleCard.Root as="li">
        <CollapsibleCard.Header>
          <Flex gap="spacingS">
            <Label size="small" color="danger">
              {'Error'}
            </Label>
            <Text>{'Sending data failed'}</Text>
          </Flex>
        </CollapsibleCard.Header>
        <CollapsibleCard.Body>
          <DataList.Root emphasize="value">
            <DataList.Row>
              <DataList.Label>{'Level'}</DataList.Label>
              <DataList.Value>
                <Label size="small" color="danger">
                  {'Error'}
                </Label>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Date occurred'}</DataList.Label>
              <DataList.Value>
                <time dateTime="2023-01-19T07:38:28.788Z">
                  {'19.01.2023 08:38:28'}
                </time>
              </DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Event ID'}</DataList.Label>
              <DataList.Value>{'DLhy2w'}</DataList.Value>
            </DataList.Row>
            <DataList.Row>
              <DataList.Label>{'Message'}</DataList.Label>
              <DataList.Value>{'Sending data failed'}</DataList.Value>
            </DataList.Row>
          </DataList.Root>
        </CollapsibleCard.Body>
        <CollapsibleCard.Footer>
          <Button
            variant="outline"
            size="small"
            leftIcon={<SvgIcon iconName="copy" />}
          >
            {'Copy as JSON'}
          </Button>
        </CollapsibleCard.Footer>
      </CollapsibleCard.Root>
    </Flex>
  </Flex>
</ContentBlock>
```

---

## API Reference

### CollapsibleCard.Root

| Name             | Type                        | Default      | Description                                                                                                                                                                                                                                   | Required |
| ---------------- | --------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`            | `StitchesCss`               |              | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |
| `isOpen`         | `boolean`                   | `false`      | The controlled open state of the component. Use in conjunction with `onIsOpenChange`.                                                                                                                                                         |          |
| `defaultIsOpen`  | `boolean`                   |              | The open state of the collapsible card when it's first rendered. Use when you do not need to control open state.                                                                                                                              |          |
| `onIsOpenChange` | `(isOpen: boolean) => void` |              | Event handler called when the open state of the component changes.                                                                                                                                                                            |          |
| `size`           | `"medium" \| "small"`       | `"medium"`   | The size of the collapsible card.                                                                                                                                                                                                             |          |
| `unmountOnExit`  | `boolean`                   | `false`      | When `true`, collapsible content will unmount when exit animation is done.                                                                                                                                                                    |          |
| `onExitComplete` | `() => void`                | `() => void` | Event handler called when the collapsible content has completed animating out and is to be unmounted.                                                                                                                                         |          |

### CollapsibleCard.Header

<Callout variant="tip">

In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing.

</Callout>

| Name  | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### CollapsibleCard.Body

<Callout variant="tip">

In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing.

</Callout>

| Name  | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### CollapsibleCard.Footer

<Callout variant="tip">

In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing.

</Callout>

| Name      | Type                                                      | Default         | Description                                                                                                                                                                                                                                                                                  | Required |
| --------- | --------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`      | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`           | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`     | `StitchesCss`                                             |                 | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `variant` | `"withBackground" \| "withDivider"`                       | `"withDivider"` | Visual variant of the card footer.                                                                                                                                                                                                                                                           |          |
