Card
A bordered surface that groups a header, content and footer, with an optional action slot.
npx shadcn@latest add @velaui/cardpnpm dlx velaui add @velaui/cardyarn dlx shadcn@latest add @velaui/cardbunx --bun shadcn@latest add @velaui/cardveni add cardInstalls the copy of vela-ui that veni-builder serves to Venizia apps; veni-builder serves the Radix UI copy only, so this tab exists for that base alone.
npx shadcn@latest add @velaui/cardpnpm dlx velaui add @velaui/cardyarn dlx shadcn@latest add @velaui/cardbunx --bun shadcn@latest add @velaui/cardExamples
- Default
- Small
Usage
Props
Card
| Prop | Type | Default |
|---|---|---|
size | "sm" | "default" | "default" |
Takes these and every prop of CardProps.
CardHeader
Takes every prop of CardHeaderProps.
CardFooter
Takes every prop of CardFooterProps.
CardTitle
Takes every prop of CardTitleProps.
CardAction
Takes every prop of CardActionProps.
CardDescription
Takes every prop of CardDescriptionProps.
CardContent
Takes every prop of CardContentProps.
Dependencies
- npm
- none besides React
- Installs with it
- nothing else
Source
components/ui/card.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
export type CardProps = React.ComponentProps<"div"> & { size?: "default" | "sm" };
function Card({
className,
size = "default",
...props
}: CardProps) {
return (
<div
data-slot="card"
data-size={size}
className={cn(
"group/card flex flex-col gap-4 overflow-hidden rounded-xl border border-border-default bg-bg-main py-(--card-spacing) text-sm text-text-strong shadow-[0px_0px_1px_0px_rgba(10,10,10,0.04),0px_0.5px_2px_-1px_rgba(10,10,10,0.12),0px_2px_4px_-2px_rgba(10,10,10,0.08)] [--card-spacing:--spacing(6)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className,
)}
{...props}
/>
);
}
export type CardHeaderProps = React.ComponentProps<"div">;
function CardHeader({ className, ...props }: CardHeaderProps) {
return (
<div
data-slot="card-header"
className={cn(
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className,
)}
{...props}
/>
);
}
export type CardTitleProps = React.ComponentProps<"div">;
function CardTitle({ className, ...props }: CardTitleProps) {
return (
<div
data-slot="card-title"
className={cn(
"text-base leading-snug font-semibold text-text-strong group-data-[size=sm]/card:text-sm",
className,
)}
{...props}
/>
);
}
export type CardDescriptionProps = React.ComponentProps<"div">;
function CardDescription({ className, ...props }: CardDescriptionProps) {
return (
<div
data-slot="card-description"
className={cn("text-sm text-text-muted", className)}
{...props}
/>
);
}
export type CardActionProps = React.ComponentProps<"div">;
function CardAction({ className, ...props }: CardActionProps) {
return (
<div
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
)}
{...props}
/>
);
}
export type CardContentProps = React.ComponentProps<"div">;
function CardContent({ className, ...props }: CardContentProps) {
return (
<div
data-slot="card-content"
className={cn("px-(--card-spacing)", className)}
{...props}
/>
);
}
export type CardFooterProps = React.ComponentProps<"div">;
function CardFooter({ className, ...props }: CardFooterProps) {
return (
<div
data-slot="card-footer"
className={cn(
"flex items-center rounded-b-xl border-t border-border-default bg-bg-surface-1 p-(--card-spacing)",
className,
)}
{...props}
/>
);
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardContent,
};