---
title: Card
description: A flexible container component with customizable themes, borders, and aspect ratios
---

```tsx
'use client';

import { Card } from '@/ui/cards/Card';

export function CardDemo() {
  return (
    <Card className="p-24 w-full max-w-sm">
      <h3 className="text-18 font-bold mb-8">Card Title</h3>
      <p className="text-14 text-grey">
        This is a simple card component with bordered theme and custom format.
      </p>
    </Card>
  );
}
```

## Installation

Using the CLI:

```bash
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/card.json
```

Or manually, copy the following code into `/ui/card.tsx`:

```tsx
import type { ComponentPropsWithoutRef, ElementType } from 'react';
import cx from 'clsx';
import { CARD_ASPECT_RATIOS } from './CardAspectRatios';

type CARD_THEME = 'none' | 'bordered' | 'frame';

export type CardProps<T extends ElementType = 'div'> = {
  component?: string;
  /**
   * By default the card has a border.
   * Set to false to remove it.
   */
  border?: boolean;
  format?: keyof typeof CARD_ASPECT_RATIOS;
  theme?: CARD_THEME | CARD_THEME[];
} & ComponentPropsWithoutRef<T>;

export function Card<T extends ElementType = 'div'>({
  children,
  className,
  component = 'div',
  format = 'custom',
  theme = 'bordered',
  ...attrs
}: CardProps<T>) {
  const Cmp = component as ElementType;
  const resolvedTheme = ([] as CARD_THEME[]).concat(theme).join(' ');

  return (
    <Cmp
      {...attrs}
      className={cx(
        CARD_ASPECT_RATIOS[format],
        'relative isolate rounded-16',
        {
          'bg-white': !className?.includes('bg-'),
          'group overflow-hidden': resolvedTheme.includes('frame'),
          'border border-lightGrey': resolvedTheme.includes('bordered'),
        },
        className,
      )}
    >
      {children}
    </Cmp>
  );
}
```

## Usage

```tsx showLineNumbers
import { Card } from '@/docs/lib/ui/card';

export function Component() {
  return (
    <Card className="p-24">
      <h3 className="text-18 font-bold mb-8">Card Title</h3>
      <p className="text-14 text-grey">This is a simple card component with bordered theme.</p>
    </Card>
  );
}
```

## API Reference

### Card

| Prop        | Type                                                   | Default      | Description                                                                                                                                                                      |
| ----------- | ------------------------------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `component` | `string`                                               | `"div"`      | The HTML element or component to render as. Can be any valid HTML element like "section", "article", etc.                                                                        |
| `border`    | `boolean`                                              | `undefined`  | Deprecated: Use `theme` prop instead. When set to false, removes the border.                                                                                                     |
| `format`    | `"horizontal" \| "vertical" \| "square" \| "custom"`   | `"custom"`   | The aspect ratio format of the card. "custom" applies no aspect ratio constraint.                                                                                                |
| `theme`     | `"none" \| "bordered" \| "frame" \| Array<CARD_THEME>` | `"bordered"` | The visual theme of the card. Can be a single theme or an array of themes. "bordered" adds a border, "frame" adds overflow hidden and group styling, "none" removes all theming. |
| `className` | `string`                                               | `undefined`  | Additional CSS classes to apply to the card.                                                                                                                                     |

## Examples

```tsx
'use client';

import { Card } from '@/ui/cards/Card';
import { CardBackground } from '@/ui/cards/CardBackground';
import { CardClickable } from '@/ui/cards/CardClickable';
import { HeadingGroup } from '@/ui/heading/HeadingGroup';
import { Button } from '@/ui/buttons/Button';

export function CardButtonDemo() {
  return (
    <Card theme="frame" format="horizontal" className="max-w-380">
      <CardBackground
        src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
        alt="Mountain landscape"
      >
        <CardClickable coverLink className="w-full justify-between">
          <HeadingGroup level={2} subtitle="Winter">
            Mountain Resort
          </HeadingGroup>
          <Button
            color="white"
            theme="outline"
            variant="circle"
            icon="ArrowDefaultRight"
            aria-label="View details"
            className="pointer-events-auto shrink-0"
          />
        </CardClickable>
      </CardBackground>
    </Card>
  );
}
```

```tsx
'use client';

import { Card } from '@/ui/cards/Card';
import { CardBackground } from '@/ui/cards/CardBackground';
import { CardClickable } from '@/ui/cards/CardClickable';
import { HeadingGroup } from '@/ui/heading/HeadingGroup';
import { Tag } from '@/ui/Tag';

export function CardTagDemo() {
  return (
    <Card theme="frame" format="horizontal" className="max-w-380">
      <CardBackground
        src="https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a"
        alt="Beach resort"
      >
        <Tag label="Best Seller" className="mx-12 mt-12 self-start px-8" />
        <CardClickable coverLink>
          <HeadingGroup level={2} subtitle="Caribbean">
            Beach Paradise
          </HeadingGroup>
        </CardClickable>
      </CardBackground>
    </Card>
  );
}
```

```tsx
'use client';

import { Card } from '@/ui/cards/Card';
import { Chip } from '@/ui/Chip';
import { Icon } from '@clubmed/trident-icons';

export function CardNoBorderDemo() {
  return (
    <Card theme="none" className="p-24 w-full max-w-sm">
      <Chip theme="solid" color="lightSand" size="size-48">
        <Icon name="Star" width="24px" />
      </Chip>
      <h3 className="text-18 font-bold mt-12 mb-8">Premium Service</h3>
      <p className="text-14 text-grey">Experience luxury with our exclusive offerings.</p>
    </Card>
  );
}
```

```tsx
'use client';

import { Card } from '@/ui/cards/Card';
import { Chip } from '@/ui/Chip';
import { Icon } from '@clubmed/trident-icons';

export function CardListDemo() {
  return (
    <Card className="p-20 w-full max-w-sm">
      <Chip theme="solid" color="lightSand" size="size-48" className="mb-12">
        <Icon name="Check" width="24px" />
      </Chip>
      <h3 className="text-18 font-bold mb-12">What's Included</h3>
      <ul className="list-disc ps-12 text-14 space-y-4">
        <li>All meals included</li>
        <li>Premium accommodation</li>
        <li>Activity pass</li>
      </ul>
    </Card>
  );
}
```

## Notes

- The Card component is polymorphic and can be rendered as any HTML element using the `component` prop
- By default, the card has a white background (`bg-white`) unless a background class is explicitly provided in `className`
- The card has rounded corners with a border radius of 16px (`rounded-16`)
- When using `format` prop, the card will automatically apply the corresponding aspect ratio class
- The `theme` prop accepts either a single value or an array, allowing you to combine multiple themes (e.g., `["bordered", "frame"]`)
- When `theme` includes "frame", the card becomes a group container with overflow hidden, useful for image cards with hover effects
