Card
Groups a focused piece of content with optional header, body, and actions.
Preview
Example code
Weekly digest
A concise summary of activity across your workspace.
- Updates
- 24
- Contributors
- 8
Playground
materialSets an opaque paper or translucent glass surface.
Usage
tsx
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "earthling-ui/card";
export function Example() {
return (
<>
<Card material="paper">
<CardHeader>
<CardTitle>Weekly digest</CardTitle>
<CardDescription>Activity across your workspace.</CardDescription>
</CardHeader>
<CardContent>24 updates from 8 contributors.</CardContent>
<CardFooter>
<button type="button">Open digest</button>
</CardFooter>
</Card>
</>
);
}
- Use paper for an opaque content surface and glass when underlying color should remain visible.
- Keep the heading level appropriate to the surrounding page; CardTitle renders an h3 by default.
- Place related actions in CardFooter and keep the whole card non-interactive when it contains buttons or links.
Installation
Start with the project setup for React and Tailwind CSS 4. Both paths use the same component and theme.
Import package
Own the source
bash
npm install earthling-uiUse the component import shown above. Package updates keep the implementation current.
API reference
Declarations from the current library build, including inherited primitive props. Playground controls above show selected options; they are not the complete API.
tsx
// Generated by dts-bundle-generator v9.5.1
import { VariantProps } from 'class-variance-authority';
import { ComponentProps } from 'react';
export declare const cardVariants: (props?: ({
material?: "paper" | "glass" | null | undefined;
interactive?: boolean | null | undefined;
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
export interface CardProps extends ComponentProps<"div">, VariantProps<typeof cardVariants> {
asChild?: boolean;
}
export declare const Card: import("react").ForwardRefExoticComponent<Omit<CardProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
export declare const CardHeader: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
export declare const CardTitle: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & import("react").RefAttributes<HTMLHeadingElement>>;
export declare const CardDescription: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
export declare const CardContent: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
export declare const CardFooter: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
export {};Runtime dependencies: @radix-ui/react-slot, class-variance-authority, cnfast.
Source
Use the eject command to copy this implementation with its required helpers and project-specific imports.
View Card implementation
tsx
"use client";
import { cn } from "@/utils/cn";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { type ComponentProps, forwardRef } from "react";
const cardVariants = cva("relative rounded-lg border text-foreground", {
variants: {
material: {
paper: "border-current/10 bg-surface shadow-xs",
glass:
"border-current/10 bg-surface/75 shadow-xs backdrop-blur-sm before:pointer-events-none before:absolute before:inset-[-1px] before:rounded-[inherit] before:bg-[linear-gradient(var(--color-light),transparent_45%)] before:p-px before:[mask-clip:content-box,_border-box] before:[mask-composite:exclude] before:[mask-image:linear-gradient(#000,#000),_linear-gradient(#000,#000)] before:[mask-origin:content-box,_border-box] before:select-none",
},
interactive: {
true: "cursor-pointer hover:border-current/20 hover:bg-current/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-outline",
false: "",
},
},
compoundVariants: [
{
material: "glass",
interactive: true,
className: "hover:bg-surface/90",
},
],
defaultVariants: {
material: "paper",
interactive: false,
},
});
export interface CardProps
extends ComponentProps<"div">, VariantProps<typeof cardVariants> {
asChild?: boolean;
}
const Card = forwardRef<HTMLDivElement, CardProps>(
({ className, material, interactive, asChild, ...props }, ref) => {
const Comp = asChild ? Slot : "div";
return (
<Comp
ref={ref}
className={cn(cardVariants({ material, interactive }), className)}
{...props}
/>
);
},
);
Card.displayName = "Card";
const CardHeader = forwardRef<HTMLDivElement, ComponentProps<"div">>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
),
);
CardHeader.displayName = "CardHeader";
const CardTitle = forwardRef<HTMLHeadingElement, ComponentProps<"h3">>(
({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight text-balance",
className,
)}
{...props}
/>
),
);
CardTitle.displayName = "CardTitle";
const CardDescription = forwardRef<HTMLParagraphElement, ComponentProps<"p">>(
({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground text-pretty", className)}
{...props}
/>
),
);
CardDescription.displayName = "CardDescription";
const CardContent = forwardRef<HTMLDivElement, ComponentProps<"div">>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
),
);
CardContent.displayName = "CardContent";
const CardFooter = forwardRef<HTMLDivElement, ComponentProps<"div">>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
),
);
CardFooter.displayName = "CardFooter";
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
cardVariants,
};