Card
Interactive UI Explorer
아래에서 각 컴포넌트의 다양한 Variants와 States를 문서화된 형태로 테스트해볼 수 있습니다.
Live Preview
디자인 시스템 v2
일관된 토큰과 접근성을 갖춘 컴포넌트 모음.
RY3일 전 업데이트
Card
콘텐츠를 묶는 카드 컨테이너입니다. variant·padding과 CardHeader/Title/Content/Footer 조합을 지원합니다.
Variants
soft / elevated / outlined — 모던 톤은 soft·elevated를 권장합니다.
Soft
Soft
slate ring + 옅은 그림자
Live Preview
Elevated
Elevated
떠 있는 느낌의 그림자
Live Preview
Outlined
Outlined
테두리만 강조
Live Preview
구성 (Header / Content / Footer)
하위 컴포넌트를 조합해 머리말·본문·꼬리말 구조를 만듭니다.
Source Code
디자인 시스템 v2
일관된 토큰과 접근성을 갖춘 컴포넌트 모음입니다.
3일 전 업데이트
Live Preview
Implementation
제작 코드
이 컴포넌트가 실제로 어떻게 구현되어 있는지 — 본체 .tsx 파일을 그대로 보여줍니다. variant 매핑·접근성 처리·forwardRef 패턴 등 디테일을 그대로 확인할 수 있어요.
Cardtypescript
/**
* Card 컴포넌트
*
* 다양한 스타일의 카드 컴포넌트입니다.
*/
import { HTMLAttributes, forwardRef } from 'react';
import { cn } from '@/lib/cn';
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
variant?: 'default' | 'elevated' | 'outlined' | 'filled' | 'soft' | 'soft-muted';
padding?: 'none' | 'sm' | 'md' | 'lg';
}
const variantStyles: Record<NonNullable<CardProps['variant']>, string> = {
default: 'bg-white border border-black',
elevated: 'bg-white border border-black shadow-lg',
outlined: 'bg-transparent border-2 border-black',
filled: 'bg-black border border-black',
// 라이트 톤 — 부드러운 slate ring + 약한 그림자. 인사이트·콘텐츠 페이지의 정보형 카드.
soft: 'rounded-2xl bg-white border border-slate-200 shadow-sm',
// soft의 배경 muted 변형 — WIP·placeholder·보조 정보 카드.
'soft-muted': 'rounded-2xl bg-slate-50/60 border border-slate-200',
};
const paddingStyles: Record<NonNullable<CardProps['padding']>, string> = {
none: '',
sm: 'p-4',
md: 'p-6',
lg: 'p-8',
};
export const Card = forwardRef<HTMLDivElement, CardProps>(
({ className, variant = 'default', padding = 'md', children, ...props }, ref) => {
return (
<div
ref={ref}
className={cn(
'rounded-lg',
variantStyles[variant],
paddingStyles[padding],
className
)}
{...props}
>
{children}
</div>
);
}
);
Card.displayName = 'Card';
// Card 하위 컴포넌트
export const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('mb-4', className)}
{...props}
/>
)
);
CardHeader.displayName = 'CardHeader';
export const CardTitle = forwardRef<HTMLHeadingElement, HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn('text-heading3 font-semibold', className)}
{...props}
/>
)
);
CardTitle.displayName = 'CardTitle';
export const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('text-body2 text-zinc-600 dark:text-zinc-400', className)}
{...props}
/>
)
);
CardContent.displayName = 'CardContent';
export const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn('mt-4 pt-4 border-t border-zinc-200 dark:border-zinc-700', className)}
{...props}
/>
)
);
CardFooter.displayName = 'CardFooter';