# Card
> A Card is a styled container that groups related content and actions.

## Import

```jsx
import { Card } from '@gemini-suite/vera-react';
```

Card is a compound component that consists of multiple parts to help you create different kinds of card template:

- `Card.Root`: The wrapper that contains all the parts of a card.
- `Card.Header`: The header of the the card.
- `Card.Body`: The wrapper containing the card's main content.
- `Card.Footer`: The footer that is proper place to put card actions.

## Examples

### Basic

Card is a specifically-styled and flexible container that does not require specific components inside of it.

```jsx
<Card.Root>
  <Heading as="h3">{`Hello, I'm in a card 💳`}</Heading>
</Card.Root>
```

### Elevated

Often Card component is showed with elevation expressing z-axis distance to surface. Use `elevated` property to add the elevation.

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

  return (
    <Flex flow="column">
      <Switch.Root
        isActive={withElevation}
        onIsActiveChange={setWithElevation}
        size="small"
      >
        <Switch.Label>{'Show elevation'}</Switch.Label>
        <Switch.Indicator>
          <Switch.On>{'On'}</Switch.On>
          <Switch.Off>{'Off'}</Switch.Off>
        </Switch.Indicator>
      </Switch.Root>
      <Card.Root elevated={withElevation}>
        <Flex flow="column">
          <Text>{`I'm more noticeable because I'm elevated.`}</Text>
          <FakeText words="35" />
        </Flex>
      </Card.Root>
    </Flex>
  );
};
```

### Card with title, body and footer

One of the most common use cases for a Card is to combine a title (`Card.Header`), supporting body copy (`Card.Body`), and footer (`Card.Footer`) with action(s) together.

<Callout variant="tip">
  Note that components <InlineCode>Card.Header</InlineCode>,{' '}
  <InlineCode>Card.Body</InlineCode> and <InlineCode>Card.Footer</InlineCode>{' '}
  are based on slots mechanism. It means, that their order in code won't affect
  the place where they are rendered, because it is predetermined.
</Callout>

```jsx
<Flex flow="column">
  <AutoGrid>
    <Card.Root>
      <Card.Header>Card header</Card.Header>
      <Card.Body>
        Exercitation incididunt cupidatat fugiat commodo veniam nisi consectetur
        ea sint aliquip non velit esse nulla. Officia ad non nostrud ad
        consectetur reprehenderit elit do quis non labore veniam. Occaecat
        nostrud exercitation cupidatat ut sunt incididunt laborum id.
      </Card.Body>
    </Card.Root>
    <Card.Root>
      <Card.Header>Card header</Card.Header>
      <Card.Body>
        I grow to fit my grid friend, because of flex usage.
      </Card.Body>
      <Card.Footer>
        <Link isExternal>{'Text link'}</Link>
      </Card.Footer>
    </Card.Root>
    <Card.Root>
      <Card.Body>
        I have footer in other variant and it's whole surface is a clickable
        link.
      </Card.Body>
      <Card.Footer variant="withBackground" as={Link} isExternal>
        Text link
      </Card.Footer>
    </Card.Root>
    <Card.Root>
      <Card.Header>Card header</Card.Header>
      <Card.Body>
        Officia ad non nostrud ad consectetur reprehenderit elit do quis non
        labore veniam.
      </Card.Body>
      <Card.Footer as={Flex}>
        <Button>Main action</Button>
        <Button variant="outline">Secondary action</Button>
      </Card.Footer>
    </Card.Root>
  </AutoGrid>
</Flex>
```

### Sizes

Cards can be displayed in `medium` and `small` sizes. Use the `size` prop to control the size.

#### With action buttons

```jsx
<Flex flow="column">
  <Box css={{ maxWidth: 400 }}>
    <Card.Root size="medium">
      <Card.Header>Medium (default)</Card.Header>
      <Card.Body>
        Officia ad non nostrud ad consectetur reprehenderit elit do quis non
        labore veniam.
      </Card.Body>
      <Card.Footer as={Flex}>
        <Button>Main action</Button>
        <Button variant="outline">Secondary action</Button>
      </Card.Footer>
    </Card.Root>
  </Box>
  <Box css={{ maxWidth: 300 }}>
    <Card.Root size="small">
      <Card.Header variant="delta">Small</Card.Header>
      <Card.Body>
        Officia ad non nostrud ad consectetur reprehenderit elit do quis non
        labore veniam.
      </Card.Body>
      <Card.Footer as={Flex} gap="spacingS">
        <Button size="small">Main action</Button>
        <Button size="small" variant="outline">
          Secondary action
        </Button>
      </Card.Footer>
    </Card.Root>
  </Box>
</Flex>
```

#### With text link

```jsx
<Flex flow="column">
  <Box css={{ maxWidth: 400 }}>
    <Card.Root size="medium">
      <Card.Header>Medium</Card.Header>
      <Card.Body>
        Officia ad non nostrud ad consectetur reprehenderit elit do quis non
        labore veniam.
      </Card.Body>
      <Card.Footer variant="withBackground" as={Link} isExternal>
        Text link
      </Card.Footer>
    </Card.Root>
  </Box>
  <Box css={{ maxWidth: 300 }}>
    <Card.Root size="small">
      <Card.Header variant="delta">Small</Card.Header>
      <Card.Body>
        Officia ad non nostrud ad consectetur reprehenderit elit do quis non
        labore veniam.
      </Card.Body>
      <Card.Footer variant="withBackground" as={Link} isExternal>
        Text link
      </Card.Footer>
    </Card.Root>
  </Box>
</Flex>
```

### Interactive card

Use <InlineCode>interactive</InlineCode> property to add interactive state to the whole card surface indicated through a change in border.
This is useful for clickable cards, where you want to render card as a link or a button with the use of `as` prop.

```jsx
<ContentBlock gutters="none" center={false}>
  <Card.Root as="a" href="#api-reference" interactive elevated>
    <Card.Header as="div">
      <Heading as="h3">Clickable card</Heading>
      <Text as="div" marginTop="spacingXs" color="foregroundNeutralSubtle">
        {'Clickable card subtitle'}
      </Text>
    </Card.Header>
    <Card.Body>
      Clickable cards presents a preview of a piece of content and offers a
      large hit-surface to make it easy to link to the full content.
    </Card.Body>
  </Card.Root>
</ContentBlock>
```

### Adjusting spacing

Card and it's subcomponents support customizing padding values for the content displayed. Use the `padding` property to adjust the spacing within a card.

<Callout variant="tip">

You can also specify spacing values at different breakpoints since `padding` prop supports responsive syntax.

 </Callout>

```jsx
<ContentBlock gutters="none" center={false}>
  <Card.Root padding="spacingM">
    <Card.Header
      paddingX="spacingM"
      paddingTop="spacingM"
      paddingBottom="spacingS"
    >
      {'Card title'}
    </Card.Header>
    {'Custom content inside a card.'}
  </Card.Root>
</ContentBlock>
```

### Adjusting rounded corners

Card supports adjusting corners rounding with the `borderRadius` property.
Rounding may be applied responsively, which enables edges of wide card surfaces to be softened on larger screens.

```jsx
<Card.Root borderRadius={{ '@initial': 's', '@mqLargeAndUp': 'm' }}>
  <Card.Header>{'Card title'}</Card.Header>
  <Card.Body>
    <AutoGrid gap="spacingL">
      <Card.Root>
        <FakeText words="50" />
      </Card.Root>
      <Card.Root>
        <FakeText words="50" />
      </Card.Root>
    </AutoGrid>
  </Card.Body>
</Card.Root>
```

### Card with media

Cards can contain media such as image or video. It is recommended that the media span the full width of the card.
You can remove the padding from the card via `padding` prop and let the media take its entire width.
After the padding is removed, you can get it back for some parts of the content by utilizing subcomponents like `Card.Body` or any other layout component that offers spacing capabilities such as [Box](/components/layout/box#margins--paddings).

```jsx
<Box css={{ maxWidth: 300 }}>
  <Card.Root padding="none" css={{ overflow: 'hidden' }}>
    <AspectRatio ratio={16 / 9}>
      <img
        src="https://images.unsplash.com/photo-1562519990-50eb51e282b2?w=600&auto=format&fit=crop&ixlib=rb-4.0.3&q=80"
        alt="Wind turbine"
      />
    </AspectRatio>
    <Card.Body>
      {
        'Through digital platforms and innovative solutions, we deliver software and services critical to society for a cleaner, better, and more profitable future.'
      }
    </Card.Body>
    <Card.Footer>
      <Button>{'Learn more'}</Button>
    </Card.Footer>
  </Card.Root>
</Box>
```

If padding is needed, then placing inside of the `Card.Body` will add the proper padding.

```jsx
<Box css={{ maxWidth: 400 }}>
  <Card.Root>
    <Card.Header>{'Card title'}</Card.Header>
    <Card.Body>
      <Flex flow="column">
        <AspectRatio ratio={16 / 9}>
          <img
            src="https://images.unsplash.com/photo-1562519990-50eb51e282b2?w=600&auto=format&fit=crop&ixlib=rb-4.0.3&q=80"
            alt="Wind turbine"
          />
        </AspectRatio>
        <Text>
          {
            'Through digital platforms and innovative solutions, we deliver software and services critical to society for a cleaner, better, and more profitable future.'
          }
        </Text>
      </Flex>
    </Card.Body>
    <Card.Footer>
      <Button>{'Learn more'}</Button>
    </Card.Footer>
  </Card.Root>
</Box>
```

### Overflowing content

When a card has some height constraints and the content within `Card.Body` overflows the available space, the `Card.Body` becomes scrollable.
In that case, you may optionally add a divider to the `CardHeader` using `withDivider` prop to make the scrollable area visually more distinctive.

<Callout variant="tip">

It is recommended to only add `Card.Header` divider when the card content has overflow. You should use `useHasOverflow` hook for that purpose.

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

</Callout>

```jsx
() => {
  const maxCount = 5;
  const minCount = 1;
  const [count, setCount] = React.useState(minCount);
  const increment = () => setCount(c => Math.min(c + 1, maxCount));
  const decrement = () => setCount(c => Math.max(c - 1, minCount));
  const [bodyRef, _hasBodyHorizontalScroll, hasBodyVerticalScroll] =
    useHasOverflow();

  return (
    <Flex flow="column" css={{ maxWidth: 400 }}>
      <Card.Root css={{ maxHeight: 300 }}>
        <Card.Header withDivider={hasBodyVerticalScroll}>
          {'Card title'}
        </Card.Header>
        <Card.Body ref={bodyRef}>
          <Flex flow="column">
            {Array.from({ length: count }, (_, i) => (
              <FakeText words="25" key={i} />
            ))}
          </Flex>
        </Card.Body>
        <Card.Footer as={Flex} variant="withBackground">
          <Button
            leftIcon={<SvgIcon iconName="add" />}
            variant="outline"
            isDisabled={count === maxCount}
            onClick={increment}
          >
            {'Add content'}
          </Button>
          <Button
            leftIcon={<SvgIcon iconName="minus" />}
            variant="outline"
            isDisabled={count === minCount}
            onClick={decrement}
          >
            {'Remove content'}
          </Button>
        </Card.Footer>
      </Card.Root>
    </Flex>
  );
};
```

---

## API Reference

### Card.Root

<Callout variant="tip">

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

</Callout>

### Card.Header

<Callout variant="tip">

In addition to the props below, you can pass [Heading props](/components/typography/heading#api-reference).

</Callout>

### Card.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 |
| ----- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `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. |          |

### Card.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.                                                                                                                                                                                                                                                           |          |
