variant
default · elevated(shadow) · interactive 클릭 카드 · notice(accent 테두리)
state props
selected · disabled — Card가 하나의 타겟일 때만 사용
슬롯
CardHeader · CardTitle · CardDescription · CardContent · CardFooter
notice
default와 같은 배경을 유지하고 accent border로만 맥락을 표시합니다.
interactive
hover와 focus-visible 피드백이 필요한 클릭 가능한 카드에만 사용합니다.
중첩
elevated 안에 default 허용 — 인터랙티브 중첩 금지

기본

default, elevated, notice variant

기본 카드

관련 콘텐츠를 묶는 기본 컨테이너입니다.

카드 본문 내용이 여기에 들어갑니다.

강조 카드

레이어드 레이아웃에서 계층감을 주는 elevated 카드입니다.

그림자로 입체감을 더합니다.

알림 카드

시스템 안내나 주의사항을 표시하는 notice 카드입니다.

기본 카드 배경은 유지하고 브랜드 컬러 테두리로 맥락을 표시합니다.

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@olundot/ui";

export function CardBasic() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>기본 카드</CardTitle>
          <CardDescription>관련 콘텐츠를 묶는 기본 컨테이너입니다.</CardDescription>
        </CardHeader>
        <CardContent>
          <p>카드 본문 내용이 여기에 들어갑니다.</p>
        </CardContent>
      </Card>
      <Card surface="canvas" variant="elevated">
        <CardHeader>
          <CardTitle>강조 카드</CardTitle>
          <CardDescription>레이어드 레이아웃에서 계층감을 주는 elevated 카드입니다.</CardDescription>
        </CardHeader>
        <CardContent>
          <p>그림자로 입체감을 더합니다.</p>
        </CardContent>
      </Card>
      <Card surface="canvas" variant="notice">
        <CardHeader>
          <CardTitle>알림 카드</CardTitle>
          <CardDescription>시스템 안내나 주의사항을 표시하는 notice 카드입니다.</CardDescription>
        </CardHeader>
        <CardContent>
          <p>기본 카드 배경은 유지하고 브랜드 컬러 테두리로 맥락을 표시합니다.</p>
        </CardContent>
      </Card>
    </div>
  );
}
CardFooter 액션 버튼

모의고사 2회

32문항 · 45분 · 금요일까지

내과 · 외과 · 소아과 영역 통합 문제입니다. 제한 시간 내 완료해야 합니다.

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@olundot/ui";
import { Button } from "@olundot/ui";

export function CardWithFooter() {
  return (
    <Card surface="canvas" style={{ maxWidth: "400px" }}>
      <CardHeader>
        <CardTitle>모의고사 2회</CardTitle>
        <CardDescription>32문항 · 45분 · 금요일까지</CardDescription>
      </CardHeader>
      <CardContent>
        <p style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>
          내과 · 외과 · 소아과 영역 통합 문제입니다. 제한 시간 내 완료해야 합니다.
        </p>
      </CardContent>
      <CardFooter>
        <Button variant="outline" size="sm">미리보기</Button>
        <Button variant="primary" size="sm">응시 시작</Button>
      </CardFooter>
    </Card>
  );
}

클릭 가능

클릭 가능한 카드와 focus-visible

내과

강의 12개 · 문제 240문항

외과

강의 12개 · 문제 240문항

소아과

강의 12개 · 문제 240문항

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@olundot/ui";

// 클릭 가능한 카드는 hover 시 elevation과 border로 반응한다.
// 카드 전체가 단일 목적지인 경우에만 사용. 버튼/링크 중첩 금지.
export function ClickableCard() {
  return (
    <div style={{ display: "grid", gap: "12px" }}>
      {["내과", "외과", "소아과"].map((subject) => (
        <Card surface="canvas"
          key={subject}
          variant="interactive"
          tabIndex={0}
          role="button"
          aria-label={`${subject} 강의 목록 보기`}
          onClick={() => {}}
          onKeyDown={(e) => e.key === "Enter" && e.currentTarget.click()}
        >
          <CardHeader>
            <CardTitle>{subject}</CardTitle>
            <CardDescription>강의 12개 · 문제 240문항</CardDescription>
          </CardHeader>
        </Card>
      ))}
    </div>
  );
}

선택·비활성 상태

selected와 disabled 상태 prop

선택된 강의

밝은 surface와 accent border로 선택 상태를 표시합니다.

비활성 카드

Card 단일 타겟을 사용할 수 없을 때 disabled를 적용합니다.

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription } from "@olundot/ui";

export function CardStates() {
  return (
    <div style={{ display: "grid", gap: "12px" }}>
      <Card surface="canvas" selected>
        <CardHeader>
          <CardTitle>선택된 강의</CardTitle>
          <CardDescription>밝은 surface와 accent border로 선택 상태를 표시합니다.</CardDescription>
        </CardHeader>
      </Card>
      <Card surface="canvas" disabled>
        <CardHeader>
          <CardTitle>비활성 카드</CardTitle>
          <CardDescription>Card 단일 타겟을 사용할 수 없을 때 disabled를 적용합니다.</CardDescription>
        </CardHeader>
      </Card>
    </div>
  );
}

중첩 레이아웃

Card 안에 배치한 보조 Card

2026년 1학기 시험 일정

전체 교과목 기준

내과학06월 15일
외과학06월 22일
코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@olundot/ui";

export function CardNested() {
  return (
    <Card surface="canvas" variant="elevated">
      <CardHeader>
        <CardTitle>2026년 1학기 시험 일정</CardTitle>
        <CardDescription>전체 교과목 기준</CardDescription>
      </CardHeader>
      <CardContent>
        <div style={{ display: "grid", gap: "8px" }}>
          {[
            { name: "내과학", date: "06월 15일", status: "예정" },
            { name: "외과학", date: "06월 22일", status: "예정" },
          ].map((exam) => (
            <Card key={exam.name}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                <span style={{ fontWeight: 600 }}>{exam.name}</span>
                <span style={{ fontSize: "0.875rem", color: "var(--text-tertiary)" }}>{exam.date}</span>
              </div>
            </Card>
          ))}
        </div>
      </CardContent>
    </Card>
  );
}

설명 줄바꿈

한 단락 description의 줄바꿈

1줄 설명

간결한 한 줄 설명입니다.

2줄 설명

두 줄에 걸친 설명입니다. 강의 제목이나 시험 안내처럼 조금 더 긴 맥락을 담을 때 사용합니다.

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@olundot/ui";

export function CardDescriptionWrap() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>1줄 설명</CardTitle>
          <CardDescription>간결한 한 줄 설명입니다.</CardDescription>
        </CardHeader>
      </Card>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>2줄 설명</CardTitle>
          <CardDescription>
            두 줄에 걸친 설명입니다. 강의 제목이나 시험 안내처럼 조금 더 긴 맥락을 담을 때 사용합니다.
          </CardDescription>
        </CardHeader>
      </Card>
    </div>
  );
}

다중 단락 본문

다중 단락과 리스트 본문

종합 모의고사 안내

내과학 · 외과학 · 소아과학 · 산부인과학

이번 모의고사는 본 시험과 동일한 형식으로 진행됩니다.

제한 시간 내 완료하지 않으면 자동 제출되며, 부분 점수는 인정되지 않습니다.

  • 총 240문항 · 제한 시간 240분
  • 안정적인 네트워크 환경 권장
  • 응시 후 결과 확인은 즉시 가능
코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardProse } from "@olundot/ui";

// CardDescription은 짧은 한 단락에 사용합니다.
// 다중 단락과 리스트는 CardContent 안의 CardProse로 구성합니다.
export function CardMultiParagraph() {
  return (
    <Card surface="canvas">
      <CardHeader>
        <CardTitle>종합 모의고사 안내</CardTitle>
        <CardDescription>내과학 · 외과학 · 소아과학 · 산부인과학</CardDescription>
      </CardHeader>
      <CardContent>
        <CardProse>
          <p>이번 모의고사는 본 시험과 동일한 형식으로 진행됩니다.</p>
          <p>제한 시간 내 완료하지 않으면 자동 제출되며, 부분 점수는 인정되지 않습니다.</p>
          <ul>
            <li>총 240문항 · 제한 시간 240분</li>
            <li>안정적인 네트워크 환경 권장</li>
            <li>응시 후 결과 확인은 즉시 가능</li>
          </ul>
        </CardProse>
      </CardContent>
    </Card>
  );
}

콘텐츠 밀도

compact, comfortable, spacious 여백 비교

Compact

조밀한 목록 항목 — 8×12px

내과학 · 문제 120문항 · 마감 D-3

Comfortable

기본 여백 — var(--space-4)

내과학 · 문제 120문항 · 마감 D-3

Spacious

넓은 여백 — 24px

내과학 · 문제 120문항 · 마감 D-3

코드 보기tsx
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@olundot/ui";

// 현재는 CardContent 패딩으로 density를 조정합니다.
// 권장: compact=8px 12px / comfortable=16px(기본) / spacious=24px
export function CardDensity() {
  return (
    <div style={{ display: "grid", gap: "16px" }}>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>조밀</CardTitle>
          <CardDescription>조밀한 목록 항목 — 8×12px</CardDescription>
        </CardHeader>
        <CardContent style={{ padding: "8px 12px" }}>
          <p style={{ fontSize: "0.8125rem", color: "var(--text-secondary)" }}>
            내과학 · 문제 120문항 · 마감 D-3
          </p>
        </CardContent>
      </Card>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>기본</CardTitle>
          <CardDescription>기본 여백 — var(--space-4)</CardDescription>
        </CardHeader>
        <CardContent>
          <p style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>
            내과학 · 문제 120문항 · 마감 D-3
          </p>
        </CardContent>
      </Card>
      <Card surface="canvas">
        <CardHeader>
          <CardTitle>여유</CardTitle>
          <CardDescription>넓은 여백 — 24px</CardDescription>
        </CardHeader>
        <CardContent style={{ padding: "24px" }}>
          <p style={{ fontSize: "0.875rem", color: "var(--text-secondary)" }}>
            내과학 · 문제 120문항 · 마감 D-3
          </p>
        </CardContent>
      </Card>
    </div>
  );
}