rapidUI

Card

Surface container with header, title, description, content and footer slots.

Installation

pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/card.json

Installs to @/components/ui/card.

Manual installation

Copy the source into your project:

components/ui/card.tsx
import type * as React from 'react'
import { cn } from '@/lib/utils'

function Card({ className, size = 'default', ...props }: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
	return (
		// min-h-min: overflow-hidden would let a flex column shrink the card below its content and clip it; pass
		// `min-h-0` to let a card shrink and scroll inside instead
		<div
			data-slot="card"
			data-size={size}
			className={cn(
				'group/card flex min-h-min flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground border border-border [--card-spacing:--spacing(4)] 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}
		/>
	)
}

function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
	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}
		/>
	)
}

function CardTitle({
	className,
	as: Heading = 'h3',
	...props
}: React.ComponentProps<'h3'> & {
	/** Heading level to render, so the card fits the page's heading outline */
	as?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}) {
	return (
		<Heading
			data-slot="card-title"
			className={cn('font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm', className)}
			{...props}
		/>
	)
}

function CardDescription({ className, ...props }: React.ComponentProps<'p'>) {
	return <p data-slot="card-description" className={cn('text-sm text-muted-foreground', className)} {...props} />
}

function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
	return (
		<div
			data-slot="card-action"
			className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
			{...props}
		/>
	)
}

function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
	return <div data-slot="card-content" className={cn('px-(--card-spacing)', className)} {...props} />
}

function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
	return (
		<div
			data-slot="card-footer"
			className={cn('flex items-center rounded-b-xl border-t p-(--card-spacing)', className)}
			{...props}
		/>
	)
}

export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent }

A versatile card component that serves as a container for content, with support for headers, actions, footers, and various content layouts. Built with Tailwind CSS, it provides a consistent and customizable way to display grouped content.

Features

  • Composable parts: Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter
  • CardAction slot placed in the top-right corner of the header
  • Two sizes via size: default and sm (tighter spacing and smaller title)
  • Header with a divider below it (remove it with className="border-b-0 pb-0")
  • Footer with a top border
  • Edge-to-edge images when an img is the first or last child
  • data-slot attributes on every part for styling hooks
  • Custom styling support via className

Usage

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'
import { Button } from '@/components/ui/button'

export function CaseCard() {
  return (
    <Card className="w-full max-w-md">
      <CardHeader>
        <CardTitle>Extension of detached house</CardTitle>
        <CardDescription>Case 2026-04812 · Storgatan 14</CardDescription>
        <CardAction>
          <Button variant="outline" size="sm">
            Edit
          </Button>
        </CardAction>
      </CardHeader>
      <CardContent>
        <p>Received 12 February 2026. Decision due 12 March 2026.</p>
      </CardContent>
      <CardFooter>
        <Button size="sm">Open case</Button>
      </CardFooter>
    </Card>
  )
}

// Compact card
export function StatCard() {
  return (
    <Card size="sm">
      <CardHeader>
        <CardDescription>Open cases</CardDescription>
        <CardTitle>128</CardTitle>
      </CardHeader>
      <CardContent>+12 this week</CardContent>
    </Card>
  )
}

Examples

Default

A short e-service form for a parking permit, with header, content and footer.

With Action

Place a button or menu trigger in CardAction to align it with the header, here next to a list of notification settings.

Small

size="sm" reduces the card spacing and title size, which suits a row of key figures on a dashboard. The header divider is removed with className="border-b-0 pb-0".

With Image

A municipal facility card with an image area on top. An img as the first child sits edge to edge automatically; for any other element, remove the top padding with pt-0.

Case Summary

A summary of a case in case management: key facts, the case officer and a link to the full case.

Loading State

Compose Skeleton placeholders that mirror the final layout while content loads.

Props

  • Card - size?: 'default' | 'sm' (default 'default'), plus all div attributes
  • CardTitle - renders a heading; as?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6' (default 'h3'), plus all heading attributes
  • CardDescription - renders a p, plus all p attributes
  • CardHeader, CardAction, CardContent, CardFooter - all div attributes

Pick the CardTitle level that fits the page's heading outline, e.g. <CardTitle as="h2">Title</CardTitle>.

Accessibility

  • CardTitle renders a real heading (h3 by default); set as to match the page's heading levels
  • CardDescription renders a paragraph
  • Ensure interactive elements in CardAction have accessible labels
  • Ensure proper color contrast for custom backgrounds

Best Practices

  1. Content Structure:

    • Use clear hierarchy
    • Keep content concise
    • Group related information
  2. Actions:

    • Use CardAction for a single secondary action in the header
    • Put primary actions in CardFooter
  3. Responsive Design:

    • Set appropriate widths
    • Handle image scaling
    • Use size="sm" in dense layouts
  4. Loading:

    • Use Skeleton to mirror the final layout
  • Skeleton
  • Button