Skip to content
    Style: Wireframe

    Components · Layout

    Card

    A bordered panel with a title, description and footer.

    74% of the 2,073 sites in The UI Index have a card (1,540 sites).

    Used in UI Pro: Features, Testimonials

    Invite your team

    Teammates can edit every project in this workspace.

    Seats are billed per month. You can remove a member at any time.

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/card.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/card.json

    Or copy the files below into your project. They need clsx, tailwind-merge, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    card.tsx
    import type { HTMLAttributes, ReactNode } from 'react';
    import { cn } from '@/lib/utils';
    import { card } from './card.variants';
    
    export type CardProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & {
      title?: ReactNode;
      description?: ReactNode;
      footer?: ReactNode;
      /** The heading level of the title (default h3), so cards fit the page outline. */
      as?: 'h2' | 'h3' | 'h4';
    };
    
    /** A bordered panel with an optional title, description and footer. The same props in Astro and React. */
    export function Card({ title, description, footer, as: Heading = 'h3', className, children, ...props }: CardProps) {
      return (
        <div className={cn(card.root, className)} {...props}>
          {(title || description) && (
            <div className={card.header}>
              {title && <Heading className={card.title}>{title}</Heading>}
              {description && <p className={card.description}>{description}</p>}
            </div>
          )}
          {children && <div className={card.content}>{children}</div>}
          {footer && <div className={card.footer}>{footer}</div>}
        </div>
      );
    }
    card.variants.ts
    export const card = {
      root: 'flex flex-col gap-5 rounded-xl border bg-card py-5 text-card-foreground',
      header: 'grid gap-1.5 px-5',
      title: 'text-base leading-tight font-semibold tracking-[-0.01em]',
      description: 'text-sm text-muted-foreground',
      content: 'px-5 text-sm',
      footer: 'flex items-center gap-2 border-t px-5 pt-4',
    };