# Card

A card is used to group related information and tasks so our users can scan and
prioritize information more easily.

## Design & usage guidelines

A card is useful for grouping content because of its distinct visual boundaries.
However, similar to the idea that "making everything stand out means that
nothing stands out", you should be mindful in your application of cards.

A card should be the smallest-possible self-contained section of content. If you
find yourself putting a card inside of another card, the outer card should be
removed, and it may be worth re-assessing the hierarchy of your interface.

### Clickable

If clicking on the entire Card will navigate the user to a new view or perform
an action, the Card will have interactive hover and focus states.

It is important to signify to the user that the Card is clickable. This can be
done by using elevation or by using the `arrowRight` chevron icon in the Card.
Common examples of this pattern can be found in the
[Card Figma.](https://www.figma.com/design/rIIhulZvcp9M82lNOCGv16/Product%2FOnline?m=auto\&node-id=22677-10476\&t=YbmsOsxL9J6ggqVA-1)

### Elevation

By default, it should be assumed that a Card is on the same "plane" as the
surface it sits on and has no elevation.

If the Card benefits from having elevation indicated, such as when it sits
overtop another Card or is used in a Carousel fashion, the appropriate elevation
level can be set. See
[Mobile/Elevation](/storybook/mobile/?path=/story/components-layouts-and-structure-card--elevation)
for an example.

## Related components

[Content](../Content/Content.md) and [Flex](../Flex/Flex.md) are the most common
layout tools for managing the Card's children. Generally, Card is un-opinionated
about what goes inside of it.

If you require more customization over the appearance of your container,
[Box](../Box/Box.md) is the preferred way to achieve this without writing CSS.

## Content guidelines

Card headers should be sentence-cased.

| ✅ Do                    | ❌ Don't                 |
| ----------------------- | ----------------------- |
| Client property details | Client Property Details |
| Assigned team           | ASSIGNED TEAM           |
| Required deposit        | Required Deposit        |

As previously mentioned, a Card should be "self-contained" and nesting Cards
inside of other Cards should be avoided.

## Accessibility

The Card itself is already accessible and does not require any additional setup.

With that said, it should not be wrapped in an element with an `aria-label` or
`accessibilityLabel` describing it as a card. This is redundant and will cause
unexpected behaviour for screen readers. For example, wrapping a Card with an
`accessibilityLabel` on mobile hides the entire Card from screen readers.


## Configuration

### Card Types

The Card component supports three distinct types of cards:

1. **Regular Card** - A basic card without any click behavior
2. **Link Card** - A card that navigates to a URL when clicked
3. **Clickable Card** - A card that triggers a custom click handler

### Component Customization

#### Composable Usage

The Card component supports both prop-driven and composable approaches. The
standard prop-driven usage with `title` and `header` props is straightforward
and suitable for most use cases. For advanced customization needs, the Card
component also provides `Card.Header` and `Card.Body` components.

`Card.Header` is used to display custom header content of the card. `Card.Body`
is used to display the main content of the card.

Here's an example of converting a prop-driven card to a composable one when more
customization is needed:

```tsx
<Card title="Card Title" header="Header Text">
  <p>Card content</p>
</Card>
```

becomes

```tsx
<Card>
  <Card.Header>
    <Text>Card Title</Text>
  </Card.Header>
  <Card.Body>
    <p>Card content</p>
  </Card.Body>
</Card>
```

#### Link Card Example

```tsx
<Card url="/dashboard" external={true}>
  <Card.Header>
    <Text>External Link</Text>
  </Card.Header>
  <Card.Body>
    <p>Click to navigate to dashboard</p>
  </Card.Body>
</Card>
```

#### Clickable Card Example

```tsx
<Card onClick={handleClick}>
  <Card.Header>
    <Text>Interactive Card</Text>
  </Card.Header>
  <Card.Body>
    <p>Click to trigger action</p>
  </Card.Body>
</Card>
```

### Props Compatibility

The Card component uses a discriminated union pattern to ensure proper usage.
This means that the component can be one of three distinct types, each with its
own set of valid props:

* A Link Card must have a `url` prop and cannot have an `onClick` handler
* A Clickable Card must have an `onClick` prop and cannot have a `url`
* A Regular Card has neither `url` nor `onClick`

This type system ensures that each card has a clear and single responsibility
for its interaction behavior, making it impossible to create ambiguous card
states (like having both a URL and click handler).

### Styling

Cards can be customized with the following props:

* `accent`: Applies an accent color to the card
* `elevation`: Controls the card's shadow elevation ("none" | "base" | "raised"
  \| "floating")

Example with styling:

```tsx
<Card accent="purple" elevation="raised">
  <Card.Header>
    <Text>Styled Card</Text>
  </Card.Header>
  <Card.Body>
    <p>Card with purple accent and raised elevation</p>
  </Card.Body>
</Card>
```

### UNSAFE\_ props (advanced usage)

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

Card has two elements that can be targeted with classes or styles. These are the
container and the header.

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

#### UNSAFE\_className

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

```tsx
// YourComponent.tsx
<Card
  header="Custom Styled Card"
  UNSAFE_className={{
    container: styles.customCardContainer,
    header: styles.customCardHeader,
  }}
>
  <p>Card content with custom styling</p>
</Card>

// YourComponent.module.css
.customCardContainer {
  border: 2px solid var(--color-blue);
  border-radius: var(--radius-large);
}

.customCardHeader {
  background-color: var(--color-surface--background);
  border-bottom: 1px solid var(--color-border);
}
```

#### UNSAFE\_style

Use `UNSAFE_style` to apply inline custom styles to the Card.

```tsx
<Card
  header="Inline Styled Card"
  UNSAFE_style={{
    container: {
      backgroundColor: "var(--color-surface--hover)",
      transform: "rotate(1deg)",
    },
    header: {
      backgroundColor: "var(--color-blue)",
      color: "white",
    },
  }}
>
  <p>Card content with inline styling</p>
</Card>
```

### Compound Component Card

If you're using Card with its composable subcomponents, note that currently
these subcomponents are simply fragments. As such, you are free to provide any
desired markup and have no need for either UNSAFE.

```
<Card>
 <Card.Header>
  <div className="custom" style={{padding: "var(--space-base)}}>
   <Heading level={3}>My Custom Header</Heading>
  </div>
 </Card.Header>
 <Card.Body>
  <div style={{ background: "#29d", padding: "var(--space-base)"}}>
   <Text>Card content</Text>
  </div>
 </Card.Body>
</Card>
```


## Props

### Web

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `accent` | `"indigo" | "teal" | "blue" | "green" | "lime" | "yellowGreen" | "yellow" | "red" | "grey" | "white" | "greyBlue" | "lightBlue" | "purple" | "pink" | "orange" | "brown" | "navy" | ... 68 more ... | "yellowLightest"` | No | — | The `accent`, if provided, will effect the color accent at the top of the card. |
| `elevation` | `elevationProp` | No | — |  |
| `external` | `boolean` | No | — | Makes the URL open in new tab on click. |
| `header` | `string | HeaderActionProps | ReactElement<unknown, string | JSXElementConstructor<any>>` | No | — | The header props of the card. |
| `onClick` | `(event: MouseEvent<HTMLAnchorElement | HTMLDivElement, MouseEvent>) => void` | No | — | Event handler that gets called when the card is clicked. |
| `title` | `string` | No | — | @deprecated Use header instead. |
| `UNSAFE_className` | `{ container?: string; header?: string; }` | No | — | **Use at your own risk:** Custom class names for specific elements. This should only be used as a **last resort**. Us... |
| `UNSAFE_style` | `{ container?: CSSProperties; header?: CSSProperties; }` | No | — | **Use at your own risk:** Custom style for specific elements. This should only be used as a **last resort**. Using th... |
| `url` | `string` | No | — | URL that the card would navigate to once clicked. |
