Skip to main content
ENKO

콘텐츠 표시

텍스트, 미디어, 구조화된 데이터를 보여 주는 컴포넌트.

이 컴포넌트들은 제품의 액션이 아니라 정보를 담는다. Senco에서 그 정보는 대부분 돈(금액, 환율, 수수료, 상태)이다. 그래서 아래 규칙은 정렬과 정밀도, 그리고 숫자가 어느 통화인지 헷갈리지 않게 하는 데 집중한다.

컴포넌트

ComponentPurposeElement
Card거래 세부 정보와 요약 내역을 보여 준다<section> 또는 <article>
Badge상태, 범주, 개수에 라벨을 붙인다<span>
Country flag나라의 국기를 원형 이미지로 보여 준다<img>
Scroll area스크롤바 스타일을 입힌 커스텀 스크롤 컨테이너<div>
Hover cardhover하면 뜨는 상세 미리 보기<div role="dialog">
Table구조화된 데이터를 행과 열로 보여 준다<table>
List구조화된 콘텐츠를 담는 순서 없는 목록<ul>
Disclosure법적, 규제, 컴플라이언스 텍스트<section>

Card

거래 상세 레이아웃에 쓴다. 인물 정보와 결제 수단을 담은 FROM/TO 섹션, 수수료·환율·합계를 정리한 요약 내역이 여기에 들어간다.

  • 프로토타입의 data-slot="form-card" 패턴으로 만든다
  • 송금인/수취인 신원에 CountryFlag를 쓴다
  • 요약 행은 숫자를 맞추려고 tabular-nums를 쓴다

구조

┌─────────────────────────────────┐
│  Heading                        │  --ds-text-lg / 600
│  ─────────────────────────────  │  --ds-border
│  Label                  Value   │  tabular-nums, right-aligned
│  Label                  Value   │
│  ─────────────────────────────  │
│  Total                  Value   │  weight 700
└─────────────────────────────────┘
   padding: --ds-formcard-padding (space-4)
   radius:  --ds-formcard-radius (12px)
   shadow:  --ds-formcard-shadow (xs)

변형

VariantTokensUse
Form card--ds-formcard-*모바일 화면, 묶인 필드
Flow card--ds-flowcard-*: space-5 패딩, shadow-md, radius-xl송금 플로우 단계
Contact card--ds-contactcard-*목록에서 선택할 수 있는 수취인

API

type CardVariant = "form" | "flow" | "contact";

interface CardProps {
  variant?: CardVariant;            // default: "form"
  heading?: string;
  headingLevel?: 2 | 3 | 4;         // default: 3 — follows the page hierarchy, not the desired size
  as?: "section" | "article";       // default: "section"
  interactive?: false;              // a clickable card is Contact card; presentational cards have no states
  children: React.ReactNode;
}

상태

카드는 선택할 수 있는 경우가 아니면 정적이다. 선택 가능한 카드(Contact card)에는 hover, focus, selected 상태가 있다. 표시용 카드에는 상태가 없다. 여기에 hover 효과를 주면 없는 상호작용이 있는 것처럼 보인다.

StateContact card
Default--ds-contactcard-bg, --ds-contactcard-border
Hover--ds-contactcard-hover-bg, 그림자가 --ds-contactcard-hover-shadow로 올라간다
Focus-visible--ds-focus-ring
Selected--ds-primary 테두리, --ds-primary-light 채움

hover에서는 그림자만 올리고 테두리 색은 바꾸지 않는다. 테두리 변화는 선택 상태에만 써야 두 상태가 구분된다.

동작

  • 카드는 중첩하지 않는다. 카드 안에 카드가 필요하면 2단계 인셋이나 구분선으로 나눈 섹션으로 만든다. Color의 표면 층위 모델 참고.
  • 요약 행은 tabular-nums를 써서 소수점을 세로로 맞춘다. 그러지 않으면 수수료 3.50과 합계 253.50의 자릿수가 어긋나, 내역이 계산서처럼 읽히지 않는다.
  • 카드 전체를 클릭 영역으로 만드는 건 카드 자체가 컨트롤일 때뿐이다. 그 외에는 카드 안에 버튼을 둔다. 눌리는 영역과 안 눌리는 영역이 섞인 카드에서는 사용자가 엉뚱한 곳을 누른다.

콘텐츠

카드에는 제목을 단다. 제목이 없으면 테두리 친 <div>일 뿐이고, 스크린 리더 사용자는 그 영역을 건너뛸 방법이 없다.

접근성

  • 카드에는 제목을 달고, 제목 수준은 글자 크기가 아니라 페이지 위계에 맞춘다.
  • 클릭할 수 있는 카드는 클릭 핸들러를 단 div가 아니라 <button>이나 <a> 하나로 콘텐츠를 감싼다.
  • 클릭할 수 있는 카드 안에 따로 포커스를 받는 컨트롤을 두 개 넣지 않는다. 유효하지 않은 중첩이고, 키보드 동작도 정의되지 않는다.

키보드

표시용 카드는 포커스를 받지 않는다. Contact card는 <button> 하나로, 탭 정지점도 하나다.

KeyAction
Tab카드로 이동 (상호작용 가능할 때)
Enter / Space선택

토큰

--ds-formcard-bg · --ds-formcard-border · --ds-formcard-radius · --ds-formcard-shadow · --ds-formcard-padding · --ds-flowcard-* · --ds-contactcard-*

Card

From

United States flag
Carlos Rivera
United States
PayPal
carlos@paypal.me

To

Canada flag
Devon Kim
Canada
Visa
....8293
SNC-2026-0847Completed
You received$1,200.00 CAD
Service fee (%)-$24.00
Rate0.74 USD
You received$864.71

Badge

상태, 범주, 개수를 나타내는 짧은 라벨.

  • 변형: default, secondary, outline, destructive
  • 거래 목록과 상태 표시에 쓴다

구조

PartToken
점 (상태 변형)라벨까지 --ds-space-1 간격
라벨--ds-text-2xs 또는 --ds-text-xs, 굵기 500
패딩세로 --ds-space-1, 가로 --ds-space-2
Radius--ds-radius-full

배지인가 상태 표시인가

배지는 라벨이다. 상태 표시는 상태를 전하는 배지라서 색에 더해 아이콘과 텍스트가 반드시 있어야 한다. Senco의 거래 상태는 항상 상태 표시 형태로 보여 준다. Status indicators 참고.

변형

VariantDimensionFillUse
defaultstyle--ds-surface중립 라벨
secondarystyle--ds-primary-light범주
outlinestyle없음, --ds-border낮은 강조
destructivestyle--ds-error-bg주의가 필요한 개수

API

interface BadgeProps {
  variant?: "default" | "secondary" | "outline" | "destructive";  // default: "default"
  count?: number;                   // caps display at 99+
  children?: React.ReactNode;       // the label; required unless count is given
}

배지는 상호작용하지 않고, 상태를 뜻하지도 않는다. "이 송금은 대기 중"이라는 뜻을 전하려면 Status badge를 쓴다.

상태

표시용이다. 배지에는 상호작용 상태가 없다. hover 효과를 주면 없는 상호작용이 있는 것처럼 보인다.

동작

  • 배지는 자르지 않는다. 라벨이 안 들어가면 배지가 작은 게 아니라 라벨이 긴 것이다.
  • 개수 배지는 99+까지만 표시한다.
  • 배지는 상호작용하지 않는다. 누를 수 있는 칩이 필요하면 토글 그룹 항목을 쓴다.

콘텐츠

한두 단어, 또는 99+까지 표시하는 개수. 배지는 자르지 않는다. 안 들어가는 라벨은 너무 긴 것이다.

접근성

  • 배지는 텍스트로 의미를 전한다. 색으로만 구분하는 배지는 WCAG 1.4.1 위반이다.
  • 개수 배지는 숫자만 따로 읽히게 두지 않고, 배지가 붙은 대상의 접근 가능한 이름에 합친다("Activity, 3 new").

키보드

포커스를 받지 않고 상호작용하지 않는다.

토큰

--ds-surface · --ds-primary-light · --ds-error-bg · --ds-radius-full · --ds-text-2xs

Badge variants
DefaultSecondaryOutlineFailed

Country flag

일반 아바타 대신 쓰는 원형 국기 이미지. Senco에서 사용자를 식별하는 기준은 그 사람의 나라다.

  • Next.js Image로 /flags/{code}.png의 PNG를 렌더링한다
  • 크기: 16px (인라인), 20px (테이블 행), 28px (목록 항목), 36px (카드)
  • rounded-full로 원형으로 자른다

아바타 대신 국기를 쓰는 이유

Senco의 중심은 해외 송금이다. 그래서 수취인 옆에 보여 줄 가장 쓸모 있는 정보는 돈이 어느 나라로 가는지다. 프로필 사진은 사용자가 궁금해하지 않는 정보이고, 행마다 네트워크 요청을 하나씩 쓰고, 연결이 느리면 가장 먼저 깨진다.

구조

원형 이미지 하나뿐이다. 테두리, 링, 상태 점은 없다. 국기에 다른 신호를 덧붙이면 더 이상 나라로 읽히지 않는다.

변형

VariantDimensionSize
Inlinelayout16px, 항상 장식
Table rowlayout20px
List itemlayout28px
Cardlayout36px

API

interface CountryFlagProps {
  countryCode: string;              // ISO 3166-1 alpha-2
  countryName: string;              // used as alt only when decorative is false
  size?: 16 | 20 | 28 | 36;         // default: 20
  decorative?: boolean;             // default: true — the country is normally already in the text
}

size={16}에서 국기는 항상 장식으로 처리한다. 그 크기에서는 서로 구분이 안 되는 국기가 여럿 있다.

상태

StateRendering
Loaded요청한 크기로 원형 크롭
Not loaded국가 코드 이니셜 원. Save-Data나 오프라인에서는 이게 기본이다

동작

  • 나라 이름이 텍스트로 이미 보이면 국기는 장식이므로 alt=""로 둔다. 국기 말고는 나라를 알 수 없을 때만 alt="Nigeria"를 단다.
  • Save-Data나 오프라인에서는 깨진 이미지 대신 국가 코드 이니셜 원을 보여 준다. 이미지가 하나도 로드되지 않아도 금융 정보는 전부 읽을 수 있어야 한다. Design principles 참고.
  • 국기만으로 통화를 알리지 않는다. 통화는 항상 코드로 적는다.

콘텐츠

자체 콘텐츠는 없다. 장식일 때는 alt=""로 두고, 국기로만 나라를 알 수 있을 때는 alt에 국가 코드가 아니라 나라 이름을 쓴다.

접근성

  • 국기는 텍스트가 아니라 이미지라서, 국기 하나만으로 의미를 전하면 안 된다.
  • 16px에서는 비슷해 보이는 국기가 여럿이다. 인라인 크기의 국기는 항상 장식으로 처리한다.

키보드

포커스를 받지 않고 상호작용하지 않는다.

토큰

--ds-size-avatar · --ds-radius-full · --ds-surface (이니셜 대체)

Country flag
United States flag36px
Canada flag28px
Kenya flag20px
United Kingdom flag16px

Scroll area

스타일을 입힌 스크롤바가 자동으로 숨는 커스텀 스크롤 컨테이너.

  • 스크롤바는 hover하거나 스크롤할 때 나타나고, 가만히 있으면 사라진다
  • 결제 수단 목록과 긴 콘텐츠 영역에 쓴다

구조

넘치는 부분을 잘라 내는 컨테이너와, 스타일을 입힌 스크롤바로 이뤄진다. 페이드는 보기 위한 효과일 뿐이다. 스크롤바가 안 보일 때도 콘텐츠에는 접근할 수 있어야 한다.

변형

VariantDimensionUse
Verticallayout결제 수단 목록, 긴 콘텐츠
Horizontallayout모바일의 빠른 액션 줄

API

interface ScrollAreaProps {
  label: string;                    // accessible name — a scroll region without one is unnavigable
  maxHeight?: string;
  children: React.ReactNode;
}

스크롤되는 요소에 tabIndex={0}를 붙인다. 포커스를 받지 못하는 커스텀 스크롤 컨테이너는 포인터 없이 스크롤할 수 없다.

상태

StateRendering
Idle스크롤바 사라짐
Hovered or scrolling스크롤바 나타남
Focused안쪽으로 3px 실선 --ds-focus 외곽선. 탭 정지점이기 때문이다

동작

스크롤바는 hover하거나 스크롤할 때 나타나고, 가만히 있으면 사라진다. 다시 렌더링돼도 스크롤 위치는 유지한다. 동작 줄이기 설정에서는 부드러운 스크롤 대신 바로 이동한다.

콘텐츠

자체 콘텐츠는 없다. 가로 스크롤 영역에서는 처음 두 항목이 온전히 보여야 한다. 화면 밖에서 시작하는 항목은 대부분의 사용자가 끝내 발견하지 못한다.

접근성

  • 스크롤되는 영역은 키보드 사용자도 스크롤할 수 있게 포커스를 받는다(tabindex="0"). 이 처리가 없는 커스텀 스크롤 컨테이너는 마우스 없이 접근할 수 없다.
  • 영역에는 무엇이 들어 있는지 알려 주는 접근 가능한 이름을 붙인다.
  • 스크롤 동작은 prefers-reduced-motion을 따른다. 부드러운 스크롤 대신 바로 이동한다.
  • 스크롤바가 숨어도 콘텐츠에는 접근할 수 있어야 한다. 페이드는 보기 위한 효과일 뿐이다.

키보드

KeyAction
Tab영역에 포커스
↑ ↓ PageUp PageDown스크롤

토큰

--ds-gray-300 (thumb) · --ds-focus-ring

Scroll area

Hover card

hover하면 나타나는 상세 미리 보기. 국기, 이름, 위치 같은 프로필 정보를 보여 준다.

  • Tooltip보다 자세하고, 구조화된 콘텐츠를 담을 수 있다
  • hover하면 잠깐 뒤에 열린다
  • 터치에는 맞지 않으므로, 모바일에서는 다른 접근 방법을 제공한다

구조

트리거, 카드 표면, 화살표로 이뤄진다. 일반 텍스트만 담는 Tooltip과 달리 국기, 이름, 위치 같은 구조화된 콘텐츠를 담는다.

변형

하나뿐이다. 터치 환경에서는 mobileFallback으로 넘긴 Sheet가 대신한다.

API

interface HoverCardProps {
  trigger: React.ReactNode;
  children: React.ReactNode;
  openDelay?: number;               // default: 300
  closeDelay?: number;              // default: 150 — long enough to move the pointer into the card
  mobileFallback: React.ReactNode;  // required — opens as a sheet on touch
}

mobileFallback은 선택이 아니라 필수다. hover로만 볼 수 있는 콘텐츠는 이 제품 사용자 대부분에게는 없는 거나 마찬가지다.

상태

StateRendering
Hidden기본
OpeningopenDelay 뒤, --ds-ease-out
Shown포인터가 트리거나 카드 위에 있는 동안 유지
ClosingcloseDelay 뒤

터치에는 hover 상태가 아예 없다. 트리거를 탭하면 mobileFallback이 Sheet로 열린다.

동작

PropertyValue
열림 지연약 300ms
닫힘 지연약 150ms. 포인터를 카드 안으로 옮길 시간을 준다
Z-index--ds-z-popover
닫기Esc, 또는 포인터가 트리거와 카드를 모두 벗어날 때

모바일 문제

터치에는 hover가 없다. Hover card는 데스크톱에서만 덧붙는 기능이고, 안에 든 내용은 모두 다른 경로로도 볼 수 있어야 한다. 모바일에서는 탭하면 같은 내용이 시트로 열린다. hover card 안에만 있는 콘텐츠는 Senco 사용자 대부분에게 없는 거나 마찬가지다.

콘텐츠

트리거에 다 담을 수 없는 구조화된 세부 정보를 넣는다. 나라, 결제 수단, 마지막 사용 날짜 같은 것이다. 사용자가 꼭 해야 하는 액션은 넣지 않는다.

접근성

  • 포인터 hover뿐 아니라 키보드 포커스로도 열린다 (SC 1.4.13 Content on Hover or Focus).
  • 포인터를 움직이지 않고 Esc로 닫을 수 있다.
  • Hoverable: 포인터가 카드 위에 있는 동안 열려 있다.
  • Persistent: 타이머로 저절로 닫히지 않는다.
  • 안에 상호작용 콘텐츠가 있으면 포커스 트랩과 닫기 컨트롤이 필요하다. 그런 카드라면 팝오버로 만드는 편이 맞을 가능성이 높다.

키보드

KeyAction
Tab트리거에 포커스하면 카드가 열린다
Esc포인터를 움직이지 않고 닫는다

토큰

--ds-white · --ds-border · --ds-shadow-lg · --ds-radius-lg · --ds-z-popover

Hover card

Table

구조화된 데이터를 훑어보기 쉬운 격자로 보여 준다. 큰 화면의 거래 내역에 쓴다.

  • 훑어보기 쉽게 숫자 열은 오른쪽 정렬한다
  • 행에는 국기를 붙인 수취인, 금액, 상태 배지, 날짜가 나온다

구조

PartToken
헤더 배경--ds-table-header-bg
행 줄무늬--ds-table-stripe
셀 패딩세로 --ds-space-3, 가로 --ds-space-4
테두리--ds-border

변형

VariantDimensionUse
Tablelayout포인터 위주 화면
Stacked listlayout--ds-bp-mobile 미만에서 mobileRenderer로 렌더링. 가로 스크롤은 쓰지 않는다

API

interface TableColumn<T> {
  key: keyof T & string;
  header: string;
  align?: "start" | "end";          // "end" for every numeric column
  numeric?: boolean;                // applies tabular-nums
  sortable?: boolean;
}

interface TableProps<T> {
  caption: string;                  // required; may be visually hidden
  columns: Array<TableColumn<T>>;
  rows: T[];
  rowKey: (row: T) => string;
  sort?: { key: string; direction: "asc" | "desc" };
  onSortChange?: (sort: { key: string; direction: "asc" | "desc" }) => void;
  stickyHeader?: boolean;           // default: true
  mobileRenderer?: (row: T) => React.ReactNode;  // below --ds-bp-mobile the table becomes a list
}

상태

StateRendering
Default헤더 고정, 행은 --ds-table-stripe로 줄무늬
Sorted활성 헤더에 aria-sort, 라벨 옆에 방향 표시
Row hover--ds-surface, 행이 상호작용 가능할 때만
Empty헤더만 남은 빈 화면 대신, 상황에 맞는 empty state로 바꾼다
Loading최종 행 높이와 같은 스켈레톤 행

동작

  • 숫자 열은 오른쪽 정렬하고 tabular-nums를 쓴다. 텍스트 열은 시작 쪽으로 정렬한다. 숫자 열을 가운데 정렬하면 훑어 읽을 수 없다.
  • 모든 금액에는 통화 코드를 붙인다. 여러 통화를 다루는 제품에서 숫자만 적힌 테이블은 결함이다.
  • 모바일에서는 테이블을 가로 스크롤로 두지 않고 거래 행을 세로로 쌓은 목록으로 바꾼다. 금융 테이블을 가로 스크롤로 두면 금액 열이 가려지는데, 사용자가 보러 온 게 바로 그 열이다.
  • 긴 테이블에서는 헤더를 고정한다.

콘텐츠

숫자 열은 셀마다, 또는 열 헤더에 통화를 적는다. 헤더에 통화를 적었다고 해서 한 열에 여러 통화를 섞어도 되는 건 아니다.

접근성

  • <th scope="col">을 갖춘 실제 <table> 마크업을 쓴다. div로 만든 격자에는 스크린 리더가 읽을 행·열 관계가 없다.
  • 화면에서 숨기더라도 <caption>으로 테이블 이름을 붙인다.
  • 정렬 가능한 헤더는 aria-sort를 단 <th> 안에 <button>으로 만든다.
  • 행 줄무늬는 장식이다. 어떤 행인지는 행 헤더 셀로 식별한다.

키보드

KeyAction
Tab정렬 가능한 헤더와 상호작용 셀을 차례로 이동
Enter / Space포커스된 헤더의 정렬 토글

토큰

--ds-table-header-bg · --ds-table-stripe · --ds-border · --ds-space-3 · --ds-space-4

Table
ContactAmountStatusDate
Kenya flagAdaeze Okafor
-250.00 USDCompletedApr 15
Ghana flagKwame Johnson
+1,200.00 GHSProcessingApr 14
United States flagCarlos Rivera
-800.00 USDFailedApr 13

List

글머리표를 Primary 색으로 칠한 순서 없는 목록.

  • 요구사항, 기능 목록, 옵션에 쓴다
  • 눈에 띄도록 글머리표 색은 --ds-primary를 쓴다

구조

목록 컨테이너와 항목으로 이뤄진다. 중첩은 한 단계까지만 허용한다. 더 깊은 구조가 필요하면 Tree view를 쓴다.

변형

VariantDimensionElement
Unorderedtype<ul>, --ds-primary 글머리표
Orderedtype<ol>, 번호가 장식이 아니라 의미를 가질 때

API

interface ListProps {
  as?: "ul" | "ol";                 // default: "ul" — use "ol" when the order is meaning
  children: React.ReactNode;
}

상태

표시용이다.

동작

항목을 주어진 순서대로 렌더링한다. 중첩은 한 단계까지만 허용한다. 더 깊은 구조가 필요하면 Tree view를 쓴다.

콘텐츠

항목의 형태를 맞춘다. 모두 명사구로 쓰거나 모두 동사구로 쓰고, 섞지 않는다.

접근성

실제 <ul> / <ol> 마크업을 쓴다. 스크린 리더가 "list, 5 items"라고 읽어 주면 사용자는 앞으로 얼마나 남았는지 알 수 있다. 스타일만 입힌 div 묶음은 아무것도 읽어 주지 않는다. 순서가 있는 콘텐츠(단계, 순위 옵션)는 <ol>을 쓴다. 번호가 장식이 아니라 의미를 갖기 때문이다.

키보드

포커스를 받지 않고 상호작용하지 않는다.

토큰

--ds-primary (글머리표) · --ds-space-2 · --ds-text-base

List
  • •Valid government-issued photo ID
  • •Proof of residential address
  • •Active bank account or mobile wallet

Disclosure

법적, 규제, 컴플라이언스 텍스트 컨테이너.

  • 캡션 크기(12px)의 흐린 색 텍스트
  • variant별 아이콘: regulatory (ShieldCheck), crypto (TriangleAlert), biometric (Fingerprint)
  • 인라인 링크와, 필요하면 확인용 체크박스를 넣을 수 있다
VariantIconUsage
defaultNone일반 정보성 고지
regulatoryShieldCheck라이선스, 컴플라이언스, 법적 고지
cryptoTriangleAlert크립토/변동성 자산의 위험 경고
biometricFingerprint생체 정보 수집 고지

작은 텍스트는 숨긴 텍스트가 아니다

고지 텍스트는 12px에 흐린 색이라, 시스템에서 가장 작고 대비도 가장 낮다. 이게 다크 패턴으로 흐르지 않게 규칙 두 가지를 둔다.

  • 12px의 흐린 색도 4.5:1 대비를 넘긴다(--ds-muted를 #636971로 정한 이유가 바로 이것이다). 작을 뿐 흐릿하지는 않다.
  • 사용자가 직접 판단해야 하는 내용(감수할 위험, 동의할 수수료)은 고지가 아니다. 메인 플로우에 본문 크기 알림으로 띄운다. 고지에는 결정할 거리가 아니라 알아야 할 맥락만 담는다.

사용자가 월급을 환전하려는 순간에 크립토 변동성 경고를 스크롤 아래 12px로 보여 준다면, 그건 위험을 알린 게 아니라 컴플라이언스 체크 항목 하나를 채운 것일 뿐이다.

구조

inline-start에 variant 아이콘, 텍스트 블록, 그 아래 확인 체크박스(선택)로 이뤄진다. 아이콘은 aria-hidden이다. variant의 의미는 문장이 전한다.

변형

VariantDimensionIconUse
defaulttypenone일반 정보성 고지
regulatorytypeShieldCheck라이선스, 컴플라이언스, 법적 고지
cryptotypeTriangleAlert변동성 자산의 위험 경고
biometrictypeFingerprint생체 정보 수집

API

interface DisclosureProps {
  variant?: "default" | "regulatory" | "crypto" | "biometric";  // default: "default"
  acknowledgement?: {
    checked: boolean;
    onChange: (checked: boolean) => void;
    label: string;                  // the full statement being agreed to, never "I agree"
  };
  children: React.ReactNode;
}

고지에는 알아야 할 맥락을 담는다. 사용자가 결정해야 하는 내용(감수할 위험, 동의할 수수료)은 스크롤 아래 12px 텍스트가 아니라 메인 플로우에 본문 크기 Alert로 띄운다.

상태

StateRendering
Default아이콘, 12px --ds-muted 텍스트
With acknowledgement전체 문장을 라벨로 쓴 체크박스
Acknowledged체크박스 선택됨. 문장은 계속 보인다

동작

항상 펼쳐 둔다. 펼치기 컨트롤 뒤에 접어 두지 않는다. 확인 체크박스가 있으면 체크하기 전까지 제출을 막고, 체크한 뒤에도 문장은 그대로 보인다.

콘텐츠

법률 원문을 옮기지 말고 쉬운 말로 쓴다. 쉽게 풀어 쓸 수 없는 문장이라면 사용자가 내려야 할 결정일 가능성이 높고, 결정은 본문 크기 Alert로 보여 준다.

접근성

  • 확인 체크박스는 라벨이 보이는 실제 체크박스로 만든다. 라벨에는 "I agree"가 아니라 동의하는 내용 전체를 쓴다.
  • 고지 텍스트 안의 인라인 링크에도 다른 인라인 링크처럼 밑줄을 긋는다.
  • 아이콘은 aria-hidden이다. variant의 의미는 텍스트가 전한다.

키보드

KeyAction
Tab인라인 링크, 그다음 확인 체크박스로 이동
Space확인 토글

토큰

--ds-muted · --ds-text-xs · --ds-surface · --ds-radius-md

Disclosure

Transfer processing times may vary depending on the recipient's bank and country.

Senco is licensed and regulated by the Financial Services Authority. Your funds are held in segregated accounts.

Cryptocurrency values are volatile. You may lose some or all of your investment. Past performance is not indicative of future results.

디자인과 접근성

  • 카드에는 분명한 제목과 목적이 있어야 한다
  • 제목 위계는 순서대로 쓴다(단계를 건너뛰지 않는다)
  • 아이콘만으로 의미를 전하지 않는다. 항상 텍스트 라벨을 함께 둔다
  • 모든 텍스트가 대비 기준을 충족한다

여기 모든 컴포넌트에 적용되는 규칙

  • 모든 금액에는 통화 코드를 붙인다. 헤더에 통화를 적은 테이블 안에서도 예외는 없다.
  • 숫자 열은 tabular-nums로 오른쪽 정렬한다.
  • 이미지가 로드돼야만 이해되는 정보는 없다. 국기, 아바타, 미디어 모두 텍스트 대체가 있다.
  • 구조는 스타일이 아니라 마크업으로 표현한다. 테이블은 <table>, 목록은 <ul>, 제목은 제목 태그로 쓴다.
  • 표시용 표면에는 상호작용 상태를 주지 않는다. hover 효과를 주는 순간 누를 수 있다고 약속하는 셈이다.

권장과 금지

DoDon't
Right-align amounts with tabular-numsCenter a numeric column
Show "250.00 USD"Show "250.00" and rely on a flag
Stack a table into rows on mobileLet a financial table scroll horizontally
Give a clickable card a single controlPut two buttons inside a clickable card
Put decisions in a notice at body sizeBury a risk warning in 12px disclosure text

알려진 공백

  • Card의 토큰 묶음은 formcard, flowcard, contactcard 세 개다. 네 번째를 언제 추가해도 되는지에 대한 규칙은 아직 없다.
  • Hover card의 모바일 시트 대응은 이 문서에만 정의돼 있고, 컴포넌트로는 구현되지 않았다.
  • 테이블 정렬, 필터링, 빈 상태는 아직 문서가 없다.
  • 이 페이지의 컴포넌트 중 스켈레톤 변형이 정의된 것은 하나도 없다.