implement
Card

Card

A bordered surface holding one piece of the page.

Sign in
Use the email you signed up with.
import { Div } from "@implementjs/core";
import { Button } from "@/lib/components/ui/button";
import {
	Card,
	CardAction,
	CardContent,
	CardDescription,
	CardFooter,
	CardHeader,
	CardTitle,
} from "@/lib/components/ui/card";
import { Input } from "@/lib/components/ui/input";
import { Label } from "@/lib/components/ui/label";

export default function CardDemo() {
	return Card(
		{ class: "w-full max-w-sm" },
		CardHeader(
			CardTitle("Sign in"),
			CardDescription("Use the email you signed up with."),
			CardAction(Button({ variant: "link", size: "sm" }, "Sign up")),
		),
		CardContent(
			Div(
				{ class: "flex flex-col gap-4" },
				Div(
					{ class: "flex flex-col gap-2" },
					Label({ for: "card-email" }, "Email"),
					Input({ id: "card-email", type: "email", placeholder: "you@example.com" }),
				),
				Div(
					{ class: "flex flex-col gap-2" },
					Label({ for: "card-password" }, "Password"),
					Input({ id: "card-password", type: "password" }),
				),
			),
		),
		CardFooter({ class: "gap-2" }, Button({ class: "flex-1" }, "Sign in")),
	);
}

Installation

npx jsrepo add @implementjs/ui/card

Nothing else comes with it — this one stands alone on @implementjs/core and @implementjs/primitives.

Usage

import {
	Card,
	CardAction,
	CardContent,
	CardDescription,
	CardFooter,
	CardHeader,
	CardTitle,
} from "@/lib/components/ui/card";

Card(
	CardHeader(CardTitle("Sign in"), CardDescription("Use the email you signed up with.")),
	CardContent(Form()),
	CardFooter(Button({ class: "flex-1" }, "Sign in")),
);

The header is a grid

CardHeader is a grid rather than a flex row, and it grows a second column only when a CardAction is present (has-data-[slot=card-action]). That way a control in the top right does not force the title and description to know about it:

CardHeader(
	CardTitle("Sign in"),
	CardDescription("Use the email you signed up with."),
	CardAction(Button({ variant: "link", size: "sm" }, "Sign up")),
);

Add border-b to the header or border-t to the footer and the padding adjusts itself — the components watch for those classes ([.border-b]:pb-6) rather than making you add the padding too.

API Reference

Card

A bordered surface holding one self-contained piece of the page. Renders a Div; extra props are forwarded onto it.

CardHeader

A grid rather than a flex row, so CardAction can take a second column without the title and description having to know it is there. Renders a Div; extra props are forwarded onto it.

CardTitle

The card's name. Renders a Div; extra props are forwarded onto it.

CardDescription

A line under the title, in muted text. Renders a Div; extra props are forwarded onto it.

CardAction

A control in the top right of the header — a menu, a link, a switch. Renders a Div; extra props are forwarded onto it.

CardContent

The body. Renders a Div; extra props are forwarded onto it.

CardFooter

The bottom row, usually the actions. Renders a Div; extra props are forwarded onto it.