Card

A flexible container component used to group related content and actions. Cards provide a structured layout with distinct sections for headers, content, and actions.

Docs

Card Title

Card Description

Content

Footer

import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
} from "~/components/card";

export default function CardBasicDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
        <CardDescription>Card Description</CardDescription>
      </CardHeader>
      <CardContent>
        <p>Content</p>
      </CardContent>
      <CardFooter>
        <p>Footer</p>
      </CardFooter>
    </Card>
  );
}

Installation

CLI

Run the following command to add the component to your project:

npx @ark-preset/cli@latest add card

Manual

Create the recipe file at src/components/recipes/card.ts:

import { tv, type VariantProps } from "tailwind-variants";

export const cardVariants = tv({
  slots: {
    root: "flex flex-col gap-4 rounded-xl border bg-card text-card-foreground shadow-sm p-4",
    header: "flex flex-col gap-1.5",
    title: "leading-none font-semibold tracking-tight",
    description: "text-sm text-muted-foreground",
    content: "",
    footer: "flex items-center",
  },
});

export type CardVariants = VariantProps<typeof cardVariants>;

Create the component file at src/components/card/index.tsx:

import { splitProps, type Component } from "solid-js";
import { cardVariants } from "../recipes/card";
import { ark, type HTMLArkProps } from "@ark-ui/solid/factory";

const styles = cardVariants();

type CardProps = HTMLArkProps<"div">;
type CardHeaderProps = HTMLArkProps<"div">;
type CardTitleProps = HTMLArkProps<"h3">;
type CardDescriptionProps = HTMLArkProps<"p">;
type CardContentProps = HTMLArkProps<"div">;
type CardFooterProps = HTMLArkProps<"div">;

const Card: Component<CardProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.div class={styles.root({ class: local.class })} {...others} />;
};

const CardHeader: Component<CardHeaderProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.div class={styles.header({ class: local.class })} {...others} />;
};

const CardTitle: Component<CardTitleProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.h3 class={styles.title({ class: local.class })} {...others} />;
};

const CardDescription: Component<CardDescriptionProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.p class={styles.description({ class: local.class })} {...others} />;
};

const CardContent: Component<CardContentProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.div class={styles.content({ class: local.class })} {...others} />;
};

const CardFooter: Component<CardFooterProps> = (props) => {
  const [local, others] = splitProps(props, ["class"]);
  return <ark.div class={styles.footer({ class: local.class })} {...others} />;
};

export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, cardVariants };

Note: Make sure your project has the Tailwind CSS theme variables set up (--background, --foreground, --ring, --border, etc.) or override the utility classes to match your design system.

Usage

Basic Usage

Card Title

Card Description

Content

Footer

import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
} from "~/components/card";

export default function CardBasicDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
        <CardDescription>Card Description</CardDescription>
      </CardHeader>
      <CardContent>
        <p>Content</p>
      </CardContent>
      <CardFooter>
        <p>Footer</p>
      </CardFooter>
    </Card>
  );
}

Notifications

A card example displaying notification items.

Notifications

You have 3 unread messages.

Card Content

import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
} from "~/components/card";

export default function CardNotificationsDemo() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Notifications</CardTitle>
        <CardDescription>You have 3 unread messages.</CardDescription>
      </CardHeader>
      <CardContent>
        <p class="text-sm text-muted-foreground">Card Content</p>
      </CardContent>
      <CardFooter>
        <a href="#" class="text-sm text-primary underline underline-offset-4">
          View all
        </a>
      </CardFooter>
    </Card>
  );
}

API Reference

ComponentPropTypeDefault
Cardclassstring
CardHeaderclassstring
CardTitleclassstring
CardDescriptionclassstring
CardContentclassstring
CardFooterclassstring

Anatomy

A card is composed of the following parts:

PartElementDescription
CarddivThe root container.
CardHeaderdivThe header section, typically contains the title and description.
CardTitleh3The title text.
CardDescriptionpThe description text, styled as muted foreground.
CardContentdivThe main content area.
CardFooterdivThe footer section, typically used for actions.