Card
Contêiner com borda e sombra leve para agrupar conteúdo e ações relacionadas.
Clareamento dental
Sessão de consultório com gel de alta concentração.
R$ 890,00ou 10× de R$ 89,00 sem juros
'use client';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
export default function CardDemo() {
return (
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Clareamento dental</CardTitle>
<CardDescription>Sessão de consultório com gel de alta concentração.</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-1 text-sm">
<span className="font-mono text-2xl font-semibold tabular-nums">R$ 890,00</span>
<span className="text-muted-foreground">ou 10× de R$ 89,00 sem juros</span>
</CardContent>
<CardFooter className="gap-2">
<Button className="flex-1">Agendar avaliação</Button>
<Button variant="outline">Detalhes</Button>
</CardFooter>
</Card>
);
}Instalação
npx shadcn@latest add @lenstech/cardUso
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"<Card>
<CardHeader>
<CardTitle>Agenda de hoje</CardTitle>
<CardDescription>3 atendimentos confirmados.</CardDescription>
<CardAction>…</CardAction>
</CardHeader>
<CardContent>…</CardContent>
<CardFooter>…</CardFooter>
</Card>Exemplos
Com ação no cabeçalho
CardAction ocupa o canto superior direito do cabeçalho — use para "Ver todos", menus ou badges.
- 09:00Lucas MartinsLimpeza
- 10:30Patrícia GomesAvaliação ortodôntica
- 14:00Roberto NunesRestauração
'use client';
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Link } from '@/components/ui/link';
const agendamentos = [
{ hora: '09:00', paciente: 'Lucas Martins', servico: 'Limpeza' },
{ hora: '10:30', paciente: 'Patrícia Gomes', servico: 'Avaliação ortodôntica' },
{ hora: '14:00', paciente: 'Roberto Nunes', servico: 'Restauração' },
];
export default function CardWithAction() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Agenda de hoje</CardTitle>
<CardDescription>3 atendimentos confirmados.</CardDescription>
<CardAction>
<Link href="#">Ver agenda</Link>
</CardAction>
</CardHeader>
<CardContent>
<ul className="divide-y text-sm">
{agendamentos.map((a) => (
<li key={a.hora} className="flex items-center gap-3 py-2.5">
<span className="font-mono text-muted-foreground tabular-nums">{a.hora}</span>
<span className="flex-1 font-medium">{a.paciente}</span>
<span className="text-muted-foreground">{a.servico}</span>
</li>
))}
</ul>
</CardContent>
</Card>
);
}Indicadores
Para números de dashboard, use font-mono tabular-nums no CardTitle e reduza o espaçamento com gap-2.
Vendas hoje
R$ 3.482,90
+18% vs. ontem
Pedidos em aberto
8
3 aguardando pagamento
Ticket médio
R$ 127,40
Últimos 30 dias
'use client';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
const indicadores = [
{ titulo: 'Vendas hoje', valor: 'R$ 3.482,90', detalhe: '+18% vs. ontem' },
{ titulo: 'Pedidos em aberto', valor: '8', detalhe: '3 aguardando pagamento' },
{ titulo: 'Ticket médio', valor: 'R$ 127,40', detalhe: 'Últimos 30 dias' },
];
export default function CardStat() {
return (
<div className="grid w-full gap-4 sm:grid-cols-3">
{indicadores.map((i) => (
<Card key={i.titulo} className="gap-2">
<CardHeader>
<CardDescription>{i.titulo}</CardDescription>
<CardTitle className="font-mono text-2xl tabular-nums">{i.valor}</CardTitle>
</CardHeader>
<CardContent className="text-xs text-muted-foreground">{i.detalhe}</CardContent>
</Card>
))}
</div>
);
}Com divisórias
Adicione border-b no CardHeader ou border-t no CardFooter: o espaçamento extra é aplicado automaticamente.
Plano Profissional
Site + sistema de agendamento para a sua clínica.
- Agendamento online 24h
- Lembretes automáticos por WhatsApp
- Até 5 profissionais
R$ 249/mês
'use client';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
export default function CardWithBorders() {
return (
<Card className="w-full max-w-md">
<CardHeader className="border-b">
<CardTitle>Plano Profissional</CardTitle>
<CardDescription>Site + sistema de agendamento para a sua clínica.</CardDescription>
</CardHeader>
<CardContent>
<ul className="grid gap-2 text-sm text-muted-foreground">
<li>Agendamento online 24h</li>
<li>Lembretes automáticos por WhatsApp</li>
<li>Até 5 profissionais</li>
</ul>
</CardContent>
<CardFooter className="justify-between border-t">
<span className="font-mono text-lg font-semibold tabular-nums">R$ 249/mês</span>
<Button>Contratar</Button>
</CardFooter>
</Card>
);
}Componente sem interatividade
O Card é HTML puro (sem React Aria). Para um card inteiro clicável, coloque um Link
ou LinkButton dentro dele — não adicione onClick na div.
Quando usar
- Use para agrupar informações de uma mesma entidade: um plano, um pedido, um indicador, um resumo.
- Não use para cada linha de uma lista longa — prefira uma tabela ou lista com
Separator. - Não aninhe cards dentro de cards; use seções com títulos.
- Para seções que expandem, veja
Accordion.
API
Todos os subcomponentes aceitam as props de uma div (className, children…).
Prop
Type