A design system for AI and humans alikeAI와 사람이 함께 쓰는 디자인 시스템
Design system — the single source of truth (SSOT) for tokens, components, and patterns. Dark-first, light-ready, white-label from one seed color. AI fetches llms.txt, components.json to consume tokens, classes, and conventions directly; humans browse the catalog.Design system — 토큰, 컴포넌트, 패턴의 단일 진실원(SSOT)입니다. 다크 우선, 라이트 대응, 색 시드 하나로 화이트라벨. AI는 llms.txt, components.json을 fetch 해 토큰, 클래스, 규약을 그대로 소비하고, 사람은 카탈로그로 봅니다.
Agents read conventions from llms.txt, classes/variants/required-tokens/a11y from components.json, and tokens from tokens.json, then apply them to the target app. The web and local outputs are identical.에이전트는 llms.txt로 규약을, components.json으로 클래스, 변형, 필요 토큰, 접근성을, tokens.json으로 토큰을 읽어 작업 대상 앱에 반영합니다. 웹, 로컬 2채널 산출물은 동일합니다.
From the left menu, explore one component per page. Each page shows a live preview, variant gallery, required tokens, and accessibility notes. Switch theme (dark/light) and brand color instantly from the top bar.좌측 메뉴에서 컴포넌트를 1개=1페이지로 살펴봅니다. 각 페이지는 라이브 프리뷰, 변형 갤러리, 필요 토큰, 접근성 주의를 함께 보여줍니다. 다크/라이트 테마와 브랜드 색을 상단에서 즉시 전환할 수 있습니다.
Point your agent (Claude, Cursor, Copilot, …) at design.qufox.com — it reads llms.txt for conventions, components.json for classes, variants, required tokens, and a11y, and tokens.json for values, then writes qf-* markup with var(--token). Paste a prompt like these:에이전트(Claude, Cursor, Copilot 등)에게 design.qufox.com을 가리키세요 — llms.txt로 규약을, components.json으로 클래스, 변형, 필요 토큰, 접근성을, tokens.json으로 값을 읽어 qf-* + var(--token) 마크업을 만듭니다. 아래 같은 프롬프트를 붙여넣으세요:
Prompt: set up a project프롬프트: 프로젝트 설정
Set up my project using the design system at design.qufox.com.design.qufox.com 의 디자인 시스템을 사용해서 프로젝트 설정을 해줘.
Prompt: build a screen프롬프트: 화면 만들기
Build a login screen with the design.qufox.com design system.design.qufox.com 디자인 시스템으로 로그인 화면을 만들어줘.
Prompt: restyle existing UI프롬프트: 기존 UI 리스타일
Restyle this component with the design.qufox.com design system.이 컴포넌트를 design.qufox.com 디자인 시스템으로 리스타일 해줘.
Tip: for production, ask it to pin a fixed snapshot (e.g. /v0.18.0/tokens.css) instead of the always-latest root. The agent checks its own output against the rules in llms.txt — no raw values, AA contrast, visible focus, 44px touch targets.팁: 프로덕션에서는 항상-최신 루트 대신 고정 스냅샷(예: /v0.18.0/tokens.css)을 핀하도록 요청하세요. 에이전트는 llms.txt의 규칙(raw 값 금지, AA 대비, 포커스 가시, 44px 터치)으로 자기 출력을 검증합니다.
Direct load: for developers직접 로드: 사람 작업자용
Prefer to wire it up by hand? Browse the catalog, copy a component's markup from its page, and load the CSS directly — design.qufox.com outputs are CORS-enabled, so you can pull them from anywhere (like a CDN). <link>tokens.css + components.css, use qf-* classes, and set color, spacing, and radius only via var(--token).직접 연결하고 싶으신가요? 카탈로그에서 컴포넌트 페이지의 마크업을 복사하고 CSS를 직접 로드하세요 — design.qufox.com 산출물은 CORS 허용이라 어디서나 불러올 수 있습니다(CDN 처럼). tokens.css + components.css를 <link> 하고 qf-* 클래스를 쓰며, 색, 간격, radius는 var(--token)으로만 지정합니다.
Icons reference the sprite (icons.svg) via <use>, and the machine-readable outputs (components.json, tokens.json) are fetchable from the same domain.아이콘은 스프라이트(icons.svg)를 <use>로 참조하고, 기계가독 산출물(components.json, tokens.json)도 같은 도메인에서 fetch 할 수 있습니다.
Versions: latest vs pinned버전: 최신 vs 고정
The root (/tokens.css) is always the latest build — handy for prototyping and AI fetch. For production, pin a fixed snapshot — https://design.qufox.com/v0.18.0/tokens.css. See /versions.json for the published list, or vendor (copy) the build outputs.루트(/tokens.css)는 항상 최신 빌드라 프로토타이핑, AI fetch 에 편합니다. 프로덕션은 고정 스냅샷을 핀하세요 — https://design.qufox.com/v0.18.0/tokens.css. 발행 목록은 /versions.json, 또는 빌드 산출물을 벤더링(복사)해도 됩니다.
qufox is a dark-first system. Every surface, text, and border derives from a neutral scale generated along the night-lavender axis, while the violet accent carries the brand contrast.qufox는 dark-first 시스템이에요. 모든 서피스, 텍스트, 보더는 night-lavender 축을 따라 생성된 neutral scale에서 파생되고, violet accent가 브랜드 대비를 담당합니다.
Neutral scale
From the app shell to the header — every dark surface layer is drawn from here.앱 쉘부터 헤더까지 — 다크의 서피스 계층을 전부 여기서 뽑습니다.
--n-0#0E0C2A: app shell
--n-1#141232: chat
--n-2#1A1840: panel
--n-3#221F4F: elevated
--n-4#2C285E: hover
--n-5#3A3570: selected
--n-6#4D4780: border
--n-7#6B6599: disabled
--n-8#9892BF: muted
--n-9#C4BFDC: secondary
--n-10#E9D5FF: text
--n-11#F7F1FF: strong
Accent — violet
The brand accent. Links, CTAs, focus rings, and selected states.브랜드 액센트. 링크, CTA, focus ring, 선택 상태.
4px base. Most steps use 1–8, while 9+ are reserved for page-level spacing.4px base. 대부분 1–8을 사용하고, 9+는 페이지 레벨 여백.
--s-24px
--s-38px
--s-412px
--s-516px
--s-620px
--s-724px
--s-832px
--s-940px
--s-1048px
Radii
--r-xs: 4px
--r-sm: 6px
--r-md: 8px, Button
--r-lg: 10px, Input
--r-xl: 14px, Card
--r-pill: Avatar
Foundations
Elevation, Motion
In dark mode, shadows alone struggle to convey depth. Combine border and shadow to separate surface hierarchy.다크에서는 shadow만으로 깊이를 만들기 어렵습니다. border + shadow를 함께 써서 표면 위계를 분리하세요.
When the consuming app converts Markdown to HTML and wraps it in <article class="qf-prose">, the document renders in the design system's tone. Below are the Markdown source (left) and the rendered result (right) of the same document.소비 앱이 마크다운을 HTML 로 변환한 뒤 <article class="qf-prose"> 로 감싸면 문서가 디자인 시스템 톤으로 렌더됩니다. 아래는 같은 문서의 마크다운 소스(좌)와 렌더 결과(우)입니다.
Markdown sourceMarkdown 소스
# Getting Started with the API
This SDK is **simple**. For details, see the [docs](#).
## Installation
Install with `npm i @acme/sdk`.
- Issue a token
- Create a client
1. Enter the key
2. Connect
> Keep your key safe.
```js
const c = new Client(key);
await c.connect();
```
| Method | Description |
|---------|------|
| connect | Connect |
| close | Close |
---
End.
Rendered result: .qf-prose렌더 결과: .qf-prose
Getting Started with the APIAPI 시작하기
This SDK is simple. For details, see the docs.이 SDK는 간단합니다. 자세한 건 문서를 보세요.
Installation설치
Install with npm i @acme/sdk.npm i @acme/sdk 로 설치합니다.
Issue a token토큰 발급
Create a client클라이언트 생성
Enter the key키 입력
Connect연결
Keep your key safe.키는 안전하게 보관하세요.
const c = new Client(key);
await c.connect();
Method메서드
Description설명
connect
Connect연결
close
Close종료
End.끝.
Usage사용법
<!-- App: convert Markdown → HTML (marked, markdown-it, etc.), then wrap in .qf-prose -->
<article class="qf-prose">{{renderedHtml}}</article>
For the component interface (classes, required tokens, accessibility), see the Display → Prose page (/prose) or components.json.컴포넌트 인터페이스(클래스, 필요 토큰, 접근성)는 Display → Prose 페이지(/prose) 또는 components.json 참조.
Code syntax highlighting코드 구문 강조
The code blocks in this catalog are colored by a dependency-free build-time highlighter. The highlighting engine is the responsibility of the consumer (Prism, Shiki, highlight.js, etc.) or your own builder, while the colors come from the DS's theme-aware, brand-following tokens — map the highlighter's output classes to the qf-syntax__* classes below (or the --syntax-* tokens) for brand-consistent code blocks.이 카탈로그의 코드 블록은 빌드타임 무의존 하이라이터로 칠해집니다. 하이라이트 엔진은 소비처(Prism, Shiki, highlight.js 등)나 자체 빌더가 담당하고, 색은 DS의 테마 인지, 브랜드 추종 토큰이 담당합니다 — 하이라이터 출력 클래스를 아래 qf-syntax__*(또는 --syntax-* 토큰)에 매핑하면 브랜드 일관 코드 블록이 됩니다.
Layout-only, so it carries no semantics of its own. For a meaningful grouping, apply it to an appropriate element such as ul or section. Spacing is controlled via --qf-gap.레이아웃 전용이라 자체 시맨틱이 없습니다. 의미 있는 묶음이면 ul/section 등 적절한 요소에 적용하세요. 간격은 --qf-gap 으로 조절합니다.
Layout & structure
Cluster
A layout primitive that groups elements horizontally and wraps when they overflow (toolbars, tag groups, action rows).요소를 가로로 묶고 넘치면 줄바꿈하는 레이아웃 프리미티브입니다(툴바, 태그군, 액션열).
Layout-only. For an action grouping, use a container element that fits its meaning, and keep visual order in sync with DOM order.레이아웃 전용. 액션 묶음이면 의미에 맞는 컨테이너 요소를 쓰고, 시각 순서와 DOM 순서를 일치시킵니다.
Layout & structure
Grid
A responsive grid layout whose cells fill in automatically.셀이 자동으로 채워지는 반응형 그리드 레이아웃입니다.
Layout-only. Use --qf-grid-min to control the minimum cell width, and preserve DOM order when content order is meaningful.레이아웃 전용. --qf-grid-min 으로 최소 셀폭을 조절하며, 콘텐츠 순서가 의미를 가지면 DOM 순서를 유지합니다.
Layout & structure
Container
A centered body container (max width + side padding). Which one when: --narrow (640px) for forms and a single document body; --reading (720px) for list-style reading pages such as news, issues, or a blog index (fits a one-line title, a three-line summary, and one row of source chips); default (960px) for dashboards, tables, and two-column layouts; --wide (1200px) for wide tables and charts.중앙 정렬 본문 컨테이너입니다(최대폭 + 좌우 여백). 언제 무엇을 쓰나: --narrow(640px)는 폼과 단일 문서 본문. --reading(720px)은 뉴스, 이슈, 블로그 같은 목록형 읽기 화면(제목 한 줄, 요약 3줄, 출처 칩 한 줄이 들어가는 폭). 기본(960px)은 대시보드, 표, 2열 레이아웃. --wide(1200px)는 넓은 표와 차트.
Layout-only. Keeps page content width and horizontal padding consistent. Typically applied to main or section.레이아웃 전용. 페이지 본문 폭과 좌우 여백을 일관되게 유지합니다. 보통 main/section 에 적용합니다.
Layout & structure
Divider
A horizontal or vertical line that separates content.콘텐츠를 구분하는 수평 또는 수직 선입니다.
.qf-dividerlayer: generic
Preview
<hrclass="qf-divider">
Variants
qf-divider--vertical
Required tokens
--divider--s-5--s-4
Accessibility
Express a meaningful separation with hr or role=separator. If it is purely decorative, consider aria-hidden.의미 있는 구분은 hr 또는 role=separator 로 표현합니다. 순수 장식이면 aria-hidden 을 고려합니다.
Layout & structure
AppShell
A general app shell that lays out a header, sidebar, main content, and an optional right aside. Columns and the header derive from which regions you include — one, two, or three columns, with or without a header, no modifier needed. A container query collapses the sidebar and aside to a single column when the shell gets narrow (mobile). Tune widths with --sidenav-w and --aside-w.헤더, 사이드바, 본문, 우측 보조 패널을 배치하는 범용 앱 셸입니다. 어떤 영역을 넣느냐로 1, 2, 3단과 헤더 유무가 자동 결정됩니다(별도 모디파이어 불필요). 컨테이너 쿼리로 셸 폭이 좁아지면(모바일) 사이드바, aside가 접혀 단일 컬럼이 됩니다. 폭은 --sidenav-w, --aside-w로 조절합니다.
.qf-app-shelllayer: generic
Preview
Dashboard
A general app shell that lays out a header, sidebar, and main content. Columns derive from which regions you include.
<divclass="qf-app-shell"><headerclass="qf-app-shell__navbar"><navclass="qf-navbar"><spanclass="qf-navbar__brand">Acme</span><spanclass="qf-navbar__spacer"></span><aclass="qf-navbar__link"aria-current="page">Dashboard</a><aclass="qf-navbar__link">Reports</a></nav></header><navclass="qf-app-shell__sidenav qf-sidenav"><divclass="qf-sidenav__section">Menu</div><aclass="qf-sidenav__item"aria-current="page">Dashboard</a><aclass="qf-sidenav__item">Members</a><aclass="qf-sidenav__item">Settings</a></nav><mainclass="qf-app-shell__main"><h1>Dashboard</h1><p>A general app shell that lays out a header, sidebar, and main content. Columns derive from which regions you include.</p></main></div>
Examples예시
Dashboard
Header plus content — include only the navbar and main.
1 column, with header
Dashboard
Just the content area — include only main.
1 column, no header
Dashboard
Sidebar plus content under a header — the default layout.
2 columns, with header
Dashboard
Sidebar plus content, with no top header.
2 columns, no header
Dashboard
Sidebar, content, and a right aside — a three-column workspace.
3 columns, with header
Dashboard
Three columns without a header bar.
3 columns, no header
Dashboard
The same three-column markup: at a narrow width the sidebar and aside collapse to a single column. The app surfaces them via a drawer or tab bar.
This is a layout container. Place landmarks (header, nav, main) inside it so assistive technology can recognize each region. Control the sidebar width with --sidenav-w.레이아웃 컨테이너입니다. 내부에 landmark(header, nav, main)를 두어 보조기술이 영역을 인식하게 합니다. 사이드바 폭은 --sidenav-w 로 조절합니다.
Layout & structure
PageHeader
A page header that groups the page title, subtitle, and actions into a single row. --hero is for a site's first screen: a larger title (32px) and a roomier subtitle at body size and reading width.페이지 제목, 부제, 액션을 한 줄로 묶는 페이지 헤더입니다. --hero 는 사이트 첫 화면용으로 제목을 한 단계 크게(32px), 부제를 본문 크기와 가독 폭으로 넉넉히 둡니다.
Make the title an h1 (or a heading appropriate to the page hierarchy) to convey document structure. Keep the action group's visual order in sync with its DOM order.제목은 h1(또는 페이지 계층에 맞는 heading)으로 두어 문서 구조를 전달합니다. 액션 묶음은 시각/DOM 순서를 일치시킵니다.
Layout & structure
TwoCol
A two-column frame for wide screens (main column + aside). Inside qf-container--wide (1200px), from 1100px up the main column (max --container-w-reading, 720px) and the aside (--sz-aside, 300px) sit 40px apart, centered as a pair, so between 1100 and 1200 the main stays at 720 and the aside does not shrink. Below that it is one column — the main column centers like today's reading container and the aside drops below it (gap --s-10). In two columns the aside sticks under the sticky top bar (adjust with --qf-aside-top) and slides to the top when the bar hides (is-hidden). Keep the aside shorter than the viewport — about 560px, up to three sections, sized for a 768px-tall laptop (real viewport ≈ 650–680); a taller aside gets its bottom cut off.넓은 화면의 2열 틀입니다(본문 열 + 사이드 열). qf-container--wide(1200px) 안에 두면 1100px 이상에서 본문 열(최대 --container-w-reading 720px)과 사이드 열(--sz-aside 300px)이 간격 40px 로 가운데 정렬되어, 1100~1200 에서도 본문이 720 을 유지하고 사이드가 좁아지지 않습니다. 그 아래에서는 1열 — 본문 열이 지금의 reading 컨테이너처럼 가운데 오고 사이드는 본문 뒤로 내려갑니다(간격 --s-10). 2열에서 사이드는 고정 상단 바 아래에 sticky 로 붙고(--qf-aside-top 으로 바 높이 조정), 바가 is-hidden 으로 숨으면 맨 위로 미끄러집니다. 사이드는 뷰포트보다 짧게 두세요 — 768px 높이 노트북(실제 뷰포트 ≈ 650~680)을 기준으로 약 560px, 섹션 3개 이내. 길면 아래가 가려집니다.
Put the main element first and the aside after it so reading order stays main → aside in one column too. Make aside section titles h2 so they enter the outline. Keep the aside short enough that every focusable item inside it is visible while stuck.본문(main 요소)을 먼저, 사이드(aside 요소)를 뒤에 두어 1열에서도 읽기 순서가 본문 → 사이드가 되게 합니다. 사이드의 섹션 제목은 h2 로 두어 문서 개요에 들어가게 합니다. sticky 사이드가 가리는 영역이 없도록 사이드 안에는 포커스 대상이 뷰포트 안에 다 보이는 길이만 둡니다.
Layout & structure
Aside
Content of the aside column: a stack of sections (qf-aside__section), each with a title (qf-aside__title — 12px 600 caps, --text-muted, same tone as qf-keypoints__title) and a body. One step quieter than the main column (14px, --text-secondary), --s-6 between sections, no boxes or rules — the column itself is the separation. Inside go qf-ranklist (ranking), a group of qf-stat--sm (numbers), qf-chips with qf-chip__count (per-category counts), and qf-sources with qf-source--link (community links).사이드 열의 내용입니다: 섹션(qf-aside__section) 묶음, 섹션은 제목(qf-aside__title — 12px 600 대문자, --text-muted, qf-keypoints__title 과 같은 톤)과 본문. 본문보다 한 단계 조용한 톤(14px, --text-secondary)이고 섹션 사이 --s-6. 열 자체가 구분이므로 상자·선을 두르지 않습니다. 안에는 qf-ranklist(순위), qf-stat--sm 묶음(숫자), qf-chips + qf-chip__count(분류별 건수), qf-sources + qf-source--link(커뮤니티 링크) 를 둡니다.
.qf-asidelayer: generic
Preview
<asideclass="qf-aside"style="max-width:300px"><sectionclass="qf-aside__section"aria-labelledby="as1"><h2class="qf-aside__title"id="as1">Today in numbers</h2><divclass="qf-cluster"style="--qf-gap:var(--s-6)"><divclass="qf-stat qf-stat--sm"><spanclass="qf-stat__value">24</span><spanclass="qf-stat__label">issues today</span></div><divclass="qf-stat qf-stat--sm"><spanclass="qf-stat__value">12</span><spanclass="qf-stat__label">communities</span></div><divclass="qf-stat qf-stat--sm"><spanclass="qf-stat__value">3 min</span><spanclass="qf-stat__label">since update</span></div></div></section><sectionclass="qf-aside__section"aria-labelledby="as2"><h2class="qf-aside__title"id="as2">By category</h2><divclass="qf-chips"><aclass="qf-chip"href="#c1">
Politics
<spanclass="qf-chip__count">7</span></a><aclass="qf-chip"href="#c2">
Society
<spanclass="qf-chip__count">5</span></a><aclass="qf-chip"href="#c3">
Sports
<spanclass="qf-chip__count">4</span></a></div></section><sectionclass="qf-aside__section"aria-labelledby="as3"><h2class="qf-aside__title"id="as3">Communities</h2><divclass="qf-sources"><aclass="qf-source qf-source--link"href="#s1">Clien</a><aclass="qf-source qf-source--link"href="#s2">Ruliweb</a><aclass="qf-source qf-source--link"href="#s3">Ppomppu</a><aclass="qf-source qf-source--link"href="#s4">82cook</a></div></section></aside>
Use the aside element and make section titles h2 (or the heading level that fits the page). Link each section to its title with aria-labelledby so assistive technology names the region. The uppercase transform is visual only.aside 요소에 두고 섹션 제목은 h2(또는 페이지 계층에 맞는 heading)로 둡니다. 섹션마다 aria-labelledby 로 제목을 연결하면 보조기기가 영역 이름을 읽습니다. 대문자 변환은 시각 표현입니다.
Layout & structure
Footer
A footer within the reading width: a top rule, a note paragraph (qf-footer__note, 13px secondary tone, limited measure), and a link row (qf-footer__links). Keep the note to one paragraph — more small print stops being read. Links are 13px with vertical padding for a 24px+ tap target, and the row keeps its spacing when it wraps on phones. Bottom padding includes the safe area. A leading icon (e.g. RSS) inside a link sits with a --s-1 gap.읽기 폭 안의 바닥글입니다: 위 선, 안내 문단(qf-footer__note, 13px 보조 톤, 줄 길이 제한), 링크 줄(qf-footer__links). 안내는 한 문단으로 쓰기를 권합니다 — 둘 이상이면 작은 글씨가 길어져 읽히지 않습니다. 링크는 13px 에 세로 패딩으로 탭 대상 24px 이상이고 폰에서 두 줄로 감싸도 줄 사이 간격이 유지됩니다. 아래 여백은 안전 영역을 더합니다. 링크 앞에 아이콘(RSS 등)을 두면 간격 --s-1 로 붙습니다.
.qf-footerlayer: generic
Preview
<footerclass="qf-footer"><pclass="qf-footer__note">Summaries are written by AI from community posts and may be inaccurate. Check the original posts for details.</p><navclass="qf-footer__links"aria-label="Site"><ahref="#about">About</a><ahref="#removal">Correction and removal requests</a><ahref="#privacy">Privacy policy</a></nav></footer>
Use the footer element (contentinfo) and group the links in nav[aria-label] or a ul. Links rely on the link-row context plus hover underline rather than a permanent underline, so use this only in a footer link row. 13px is the floor for secondary text; do not make the note smaller.footer 요소(contentinfo)에 두고 링크 줄은 nav[aria-label] 또는 ul 로 묶습니다. 링크는 밑줄 대신 세로 패딩과 hover 밑줄을 쓰므로 바닥글 맥락(링크 줄)에서만 씁니다. 글자 13px 는 보조 정보의 바닥이며 안내 본문을 더 작게 두지 않습니다.
Make keyboard focus visible and convey the disabled state via disabled or aria-disabled. For icon-only buttons, add meaning with aria-label, and keep text contrast at AA 4.5:1. Ghost/icon buttons used as toggles (aria-pressed) show the pressed state as the selected surface; pair it with an icon or label change so state does not rely on color alone. Button labels do not wrap (white-space: nowrap); shorten long labels or give the button width. Add --touch to a standalone icon button (e.g. share next to a title) to extend a 44px hit area with a transparent ::after on touch devices while keeping its visual size (automatic inside qf-navbar). Do not use it in dense toolbars (gaps under 8px) — it would steal taps from neighbours.키보드 포커스가 보이도록 하고, 비활성은 disabled 또는 aria-disabled 로 전달합니다. 아이콘 전용 버튼은 aria-label 로 의미를 보충하고, 텍스트 대비는 AA 4.5:1 을 지킵니다. 토글(aria-pressed)로 쓰는 ghost/icon 버튼은 눌린 상태가 selected 표면으로 표시됩니다 — 아이콘·라벨 전환과 함께 두어 색에만 기대지 않습니다. 버튼 라벨은 줄바꿈하지 않습니다(white-space: nowrap) — 긴 라벨은 줄이거나 너비를 주세요. 단독으로 선 아이콘 버튼(제목 옆 공유 등)에는 --touch 를 붙이면 터치 환경에서 보이는 크기는 그대로 두고 44px 히트 영역을 투명 ::after 로 넓힙니다(qf-navbar 안은 자동). 밀집 툴바(간격 8px 미만)에는 쓰지 않습니다 — 이웃 버튼의 탭을 가로챕니다.
Actions
IconButton
A clean, icon-only button designed to sit in list rows.리스트 행에 들어가는 군더더기 없는 아이콘 전용 버튼입니다.
Since only an icon is shown, the action must always be conveyed via aria-label; keep keyboard focus visible and signal the disabled state with disabled. Do not rely on color alone to convey state.아이콘만 표시하므로 aria-label 로 동작을 반드시 전달하고, 키보드 포커스를 보이게 하며 비활성은 disabled 로 알립니다. 색만으로 상태를 전하지 않도록 합니다.
Actions
Link
An inline text link within body content.본문 안의 인라인 텍스트 링크입니다.
Built as a real a[href] to preserve keyboard and screen reader navigation, with a hover underline and sufficient contrast so meaning is not carried by color alone. The focus ring is visible. An unresolved wikilink (qf-link--unresolved) has no href and is marked aria-disabled="true", conveying the unresolved state with a dotted underline and color rather than color alone.실제 a[href] 로 만들어 키보드/스크린리더 탐색을 보존하고, hover 밑줄과 충분한 대비로 색 단독 의존을 피합니다. 포커스 ring 이 보입니다. 미해결 위키링크(qf-link--unresolved)는 href 를 비우고 aria-disabled="true" 로 표시하며, 점선 밑줄과 색으로 미해결을 색 단독이 아니게 전달합니다.
Actions
ButtonGroup
A group that joins adjacent buttons into a single unit (split actions, segments).인접한 버튼들을 한 덩어리로 결합한 그룹입니다(분할 액션, 세그먼트).
Convey the unit's meaning with role=group and aria-label. For toggle segments, set aria-pressed on each button.role=group 과 aria-label 로 묶음의 의미를 전달합니다. 토글 세그먼트면 각 버튼에 aria-pressed 를 둡니다.
Actions
CopyButton
A standalone button that copies an id, path, URL, or similar to the clipboard. Copy completion is reflected via data-copied=true (the consumer handles the toggle).id, 경로, URL 등을 클립보드에 복사하는 독립 버튼입니다. 복사 완료는 data-copied=true 로 상태를 표시합니다(토글은 소비처).
Convey the action and result with text next to the icon (Copy/Copied), and announce completion not just with color but with text and aria-live.아이콘 옆 텍스트(복사/복사됨)로 동작과 결과를 전달하고, 완료는 색뿐 아니라 텍스트, aria-live 로 알립니다.
Actions
ToTop
A round "back to top" icon button floating at the bottom right (qf-i-chevron-up). Hidden by default; consumer JS adds is-shown once the page is scrolled more than a screen. 44px tap target, with the phone safe area added. Set --qf-totop-bottom (default --safe-bottom) to lift it above a bottom ad or a mobile tab bar (qf-m-tabbar, which has a higher z-index).오른쪽 아래에 떠 있는 둥근 "맨 위로" 아이콘 버튼입니다(qf-i-chevron-up). 기본은 숨겨져 있고, 한 화면 넘게 내려갔을 때 소비처 JS 가 is-shown 을 붙이면 나타납니다. 44px 탭 대상이며 폰의 안전 영역을 더합니다. 바닥 광고나 모바일 탭바(qf-m-tabbar, z-index 가 더 높음) 위로 올릴 때는 --qf-totop-bottom 을 지정합니다(기본 --safe-bottom).
.qf-totoplayer: generic
Preview
<divstyle="position:relative;height:120px"><buttonclass="qf-totop is-shown"type="button"aria-label="Back to top"style="position:absolute"><svgclass="qf-icon qf-icon--md"aria-hidden="true"><usehref="#qf-i-chevron-up"/></svg></button></div>
Give the button aria-label="Back to top". While hidden it is visibility: hidden, so it leaves the focus order and is only tappable/focusable when shown. The focus ring is visible. On press the consumer scrolls to top and ideally moves focus to the first element of the content.button 에 aria-label="맨 위로" 를 둡니다. 숨김 상태는 visibility: hidden 이라 포커스 순서에서 빠지고, 보일 때만 탭·포커스됩니다. 포커스 링이 보입니다. 누르면 소비처가 window.scrollTo 로 올리고 포커스를 본문 첫 요소로 옮기면 좋습니다.
Convey the error state with aria-invalid="true", reinforced by the border and focus ring. Associate the label via a label element or aria-label, and tie helper text together with aria-describedby.오류 상태는 aria-invalid="true" 로 전달하며 보더와 링으로 함께 표시합니다. 라벨은 label 요소나 aria-label 로 연결하고, 안내문은 aria-describedby 로 묶습니다.
Forms & inputs
InputGroup
Groups an input with icon buttons on either side as one unit (no wrapping; the input may shrink). Example: previous/next-day arrows (qf-btn--ghost qf-btn--icon qf-btn--sm qf-btn--touch + qf-i-chevron-left/right) around a date input.입력과 양옆 아이콘 버튼을 한 덩어리로 묶습니다(줄바꿈 없음, 입력은 줄어들 수 있음). 예: 날짜 입력 양옆의 이전 날/다음 날 화살표(qf-btn--ghost qf-btn--icon qf-btn--sm qf-btn--touch + qf-i-chevron-left/right).
Give the arrow buttons an aria-label (previous day, next day) and the input a label or aria-label. Disable a button at the end of the range. The 28px arrows carry qf-btn--touch so they get a 44px hit area on touch devices (overlapping the input by 8px is acceptable).화살표 버튼에는 aria-label(이전 날, 다음 날)을 두고 입력에는 label 이나 aria-label 을 둡니다. 범위 끝에서는 버튼을 disabled 로. 화살표는 28px 라 qf-btn--touch 를 붙여 터치 환경에서 44px 히트 영역을 받습니다(입력 위로 8px 겹치는 정도는 허용).
Forms & inputs
Textarea
A multi-line text input field that adds height and vertical resizing on top of qf-input. --mono is for prompts and code (--font-mono, 12px).여러 줄 텍스트를 입력하는 입력 필드입니다. qf-input 위에 높이, 세로 리사이즈를 더합니다. --mono 는 지시문·코드 편집용(--font-mono 12px).
.qf-textarealayer: generic
Preview
<textareaclass="qf-input qf-textarea"rows="3"aria-label="Notes"placeholder="Enter a note"></textarea>
Associate the label via for/id or a wrapping label, and indicate errors with aria-invalid=true. Allow vertical-only resizing to prevent layout breakage.label 을 for/id 또는 감싼 라벨로 연결하고, 오류는 aria-invalid=true 로 표시합니다. 리사이즈는 세로만 허용해 레이아웃 깨짐을 막습니다.
Forms & inputs
Field
A form field wrapper that groups the label, control, helper text, and error message.라벨, 컨트롤, 도움말, 오류 메시지를 묶는 폼 필드 래퍼입니다.
.qf-fieldlayer: generic
Preview
<labelclass="qf-field"><spanclass="qf-field__label">Email</span><inputclass="qf-input"type="email"placeholder="you@example.com"><spanclass="qf-field__hint">Enter your work email.</span></label>
Associate the label with the control (by wrapping it or via for/id), and link error text with aria-describedby. Convey errors with text, not color alone.라벨을 컨트롤과 연결하고(감싸거나 for/id), 오류 텍스트는 aria-describedby 로 연결합니다. 색뿐 아니라 텍스트로 오류를 전달합니다.
Forms & inputs
DateRange
A range input that groups a start and end date, using the browser's native date picker for calendar selection.시작, 종료 날짜를 묶는 범위 입력입니다. 달력 선택은 브라우저 native date picker 를 사용합니다.
Associate each input with a from/to label via aria-label, and also convey the range meaning (start to end).각 input 에 from/to 라벨을 aria-label 로 연결하고, 범위 의미(시작~종료)를 함께 전달합니다.
Forms & inputs
ToggleRow
A settings toggle row that groups a title, description, and a control on the right into a single line.제목과 설명, 우측 컨트롤을 한 줄로 묶는 설정 토글 행입니다.
Associate the row's title text as the label for the switch on the right so screen readers know what is being turned on and off.행의 제목 텍스트를 우측 스위치의 라벨로 연결해 무엇을 켜고 끄는지 화면 낭독기에 전달합니다.
Forms & inputs
Switch
A switch that toggles between on and off states.켜짐, 꺼짐 상태를 토글하는 스위치입니다.
.qf-switchlayer: generic
Preview
<buttonclass="qf-switch"role="switch"aria-checked="true"aria-label="Turn on notifications"></button>
Convey state with role=switch and aria-checked, and associate a label. Make it togglable via keyboard and keep focus visible.role=switch와 aria-checked로 상태를 전달하고 라벨을 연결합니다. 키보드로 토글 가능하며 포커스가 보이게 합니다.
Forms & inputs
OtpInput
A one-time code input field where a verification code is entered one digit per box.인증 코드를 자리별로 입력하는 일회용 코드 입력란입니다.
Each digit box shows an accent ring on focus for visible focus, and errors are conveyed beyond color with aria-invalid and a danger ring. inputMode=numeric brings up the numeric keypad, and a label communicates the field's purpose.각 자리 입력은 포커스 시 accent ring으로 가시하고, 오류는 aria-invalid와 danger ring으로 색 외 상태를 함께 전합니다. inputMode=numeric로 숫자 키패드를 제공하고 라벨로 용도를 안내합니다.
Forms & inputs
PasswordStrengthMeter
Displays password strength in real time using a bar and a label.비밀번호 강도를 막대와 라벨로 실시간 표시합니다.
Strength is conveyed through label text (weak, fair, strong) alongside the data-strength bar color, avoiding reliance on color alone. aria-live announces changes in strength.강도는 data-strength 막대 색과 함께 라벨 텍스트(약함, 보통, 강함)로 전달해 색 단독 의존을 피합니다. aria-live로 강도 변화를 알립니다.
Forms & inputs
BackupCodes
A list that displays one-time recovery codes for two-factor authentication.2단계 인증의 일회용 복구 코드를 보여주는 목록입니다.
Used codes are distinguished with a strikethrough and dimmed color; it is best to also convey their state through text and not visuals alone. A monospace alignment keeps the codes legible.사용한 코드는 취소선과 함께 흐린 색으로 구분하며, 상태를 시각만이 아니라 텍스트로 함께 안내하면 좋습니다. mono 정렬로 코드 가독성을 확보합니다.
Forms & inputs
Checkbox
A checkbox for confirmations such as agreeing to terms.약관 동의 등 확인을 받는 체크박스입니다.
.qf-checkboxlayer: generic
Preview
<labelclass="qf-checkbox"><inputclass="qf-checkbox__input"type="checkbox"><spanclass="qf-checkbox__label">I agree to the terms</span></label>
Only accent-color is layered onto the native input to preserve focus-visible focus visibility. The label and input are associated so that clicking the label works and screen readers read it correctly.네이티브 input 위에 accent-color만 얹어 focus-visible 포커스 가시를 보존합니다. label과 input을 연결해 라벨 클릭과 스크린리더 읽기를 보장합니다.
Forms & inputs
Select
A dropdown select field that wraps a native select to match the design.네이티브 select 를 디자인에 맞춰 감싸는 드롭다운 선택 필드입니다.
Because the core is a native select, keyboard and screen reader behavior is preserved as-is. Associate the label via for/id, and indicate errors with aria-invalid=true.내부는 네이티브 select 라 키보드/스크린리더 동작을 그대로 보존합니다. label 을 for/id 로 연결하고, 오류는 aria-invalid=true 로 표시합니다.
Forms & inputs
Radio
Pairs a single-select radio button with its label on one row.단일 선택 라디오 버튼과 라벨을 한 행으로 묶습니다.
Group options under the same name and wrap them in qf-choice-list. Only accent-color is layered onto the native input to preserve focus visibility.같은 name 으로 그룹을 묶고 qf-choice-list 로 감쌉니다. 네이티브 input 위에 accent-color 만 얹어 포커스 가시를 보존합니다.
Forms & inputs
ChoiceList
A container that groups a set of checkboxes or radios together with a title.체크박스나 라디오 그룹을 제목과 함께 묶는 컨테이너입니다.
Build it as a fieldset and convey the group title with legend (qf-choice-list__legend). Use radio for single selection and checkbox for multiple selection.fieldset 으로 만들고 legend(qf-choice-list__legend)로 그룹 제목을 전달합니다. 단일 선택은 radio, 다중 선택은 checkbox 를 씁니다.
Forms & inputs
FormLayout
A layout that arranges form fields vertically and provides horizontal rows and an action row.폼 필드를 세로로 배치하고 가로 행과 액션열을 제공하는 레이아웃입니다.
Apply it to a form element, and associate each field's label/hint/error via qf-field. __row wraps automatically at narrow widths.form 요소에 적용하고 각 필드는 qf-field 로 라벨/힌트/에러를 연결합니다. __row 는 좁은 폭에서 자동 줄바꿈됩니다.
Forms & inputs
Search
A search input field with an icon and a clear button.아이콘과 클리어 버튼을 갖춘 검색 입력 필드입니다.
Give the input[type="search"] an aria-label or an associated label. Mark the icon aria-hidden, and give the clear button an aria-label (e.g. "Clear search").input[type=search] 에 aria-label 또는 연결된 label 을 둡니다. 아이콘은 aria-hidden, 클리어 버튼에는 aria-label(예: 검색어 지우기).
Forms & inputs
Slider
A slider for selecting a value from a range.범위 값을 선택하는 슬라이더입니다.
Because it's a native input[type="range"], keyboard operation and value communication come for free. Associate a label, and use aria-valuetext to supplement units when needed.네이티브 input[type=range] 라 키보드 조작과 값 전달이 기본 제공됩니다. label 을 연결하고 필요 시 aria-valuetext 로 단위를 보충합니다.
Forms & inputs
NumberInput
A numeric input field with increment and decrement buttons.증감 버튼이 있는 숫자 입력 필드입니다.
The field is an input[type="number", inputmode="numeric"] with an associated label. Give the stepper buttons an aria-label (e.g. "Increment" / "Decrement"), and let the input remain the source of truth for the value.field 는 input[type=number, inputmode=numeric] 에 label 연결. 증감 버튼에는 aria-label(예: 1 증가/감소)을 두고, 값은 input 이 권위를 가집니다.
Forms & inputs
FileDrop
A general-purpose upload zone for dropping files via drag-and-drop or clicking to browse.파일을 끌어다 놓거나 클릭해 올리는 범용 업로드 영역입니다.
.qf-file-droplayer: generic
Preview
<labelclass="qf-file-drop"><spanclass="qf-file-drop__title">Drop files here</span><span>or click to browse</span><inputtype="file"hidden></label>
Connect a real input[type="file"] to the zone (via label or click delegation) to preserve keyboard access. Convey the drag state with text in addition to --active.실제 input[type=file] 을 영역에 연결(label 또는 클릭 위임)해 키보드 접근을 보존합니다. 드래그 상태는 --active 와 함께 텍스트로도 안내합니다.
Forms & inputs
Composer
A composer that wraps an auto-expanding textarea and inline actions (send, etc.) in a focus-within pill, with a leading slot (__lead) and size variants (--sm/--lg). The rich-text format bar (__formatbar, --rich) is a chat-layer extension.focus-within 필 안에 자동확장 textarea와 인라인 액션(전송 등)을 묶는 컴포저입니다. 선행 슬롯(__lead)과 크기 변형(--sm/--lg)을 지원합니다. 리치 텍스트 포맷바(__formatbar, --rich)는 챗 확장입니다.
.qf-composerlayer: generic
Preview
<divclass="qf-composer"><divclass="qf-composer__row"><buttonclass="qf-composer__attach"aria-label="Attach"><svgclass="qf-icon"aria-hidden="true"><usehref="#qf-i-plus"/></svg></button><textareaclass="qf-composer__input"rows="1"aria-label="Message"placeholder="Type a message"></textarea><buttonclass="qf-composer__send"aria-label="Send"><svgclass="qf-icon"aria-hidden="true"><usehref="#qf-i-send"/></svg></button></div></div>
Variants
qf-composer--rich
qf-composer--sm
qf-composer--lg
Parts & more: 구성 요소, 기타: qf-composer__formatbarqf-composer__format-btnqf-composer__format-sepqf-composer__rowqf-composer__attachqf-composer__inputqf-composer__actionsqf-composer__sendqf-composer__hintqf-composer__hint-count--overqf-composer__lead
Because focus-within highlights the field with an accent border, the inner textarea disables its own outline. Formatting buttons convey their toggle state via aria-pressed. Keep the send button disabled when the input is empty, and signal a hint character-count overflow with text as well as color.focus-within 시 accent 보더로 강조하므로 내부 textarea 는 자체 outline 을 끕니다. 포맷 버튼은 aria-pressed 로 토글 상태를 전합니다. 전송 버튼은 입력이 비면 disabled 로 두고, 힌트 글자수 초과는 색만이 아니라 텍스트로도 알립니다.
Forms & inputs
Pick
An image-choice tile that behaves like a radio: pick one from a row of thumbnails. A <label class="qf-pick"> holds input[type=radio].qf-pick__input (laid transparently over the tile so the whole tile is the hit area), a frame qf-pick__frame (4:3, --bg-media, img uses object-fit: contain because the whole picture must be visible — not cover), a bottom-left tag qf-pick__tag (on-media glass, short text), and a one-line label qf-pick__label (12px, ellipsis). States: checked draws an accent outline outside the frame (2px, offset 2), focus-visible shows --ring-focus, disabled dims, hover shows a --border-strong outline. Variants: qf-pick__frame--none (dashed frame with a single word, "None"), qf-pick--muted (not a candidate — desaturated, darker image and a warning-colored tag), qf-pick--current (what is shown now — bolder label). The row is qf-picks: horizontal scroll with scroll-snap, inner padding so outlines and rings are not clipped, and the same right-edge fade as qf-chips--scroll (only when overflowing, clears at the end, is-end fallback). Tile width --sz-pick (160px; 2.1 tiles at 390px).축소 사본을 보고 하나를 고르는 이미지 선택 타일입니다(라디오 동작). <label class="qf-pick"> 안에 input[type=radio].qf-pick__input(투명하게 깔려 타일 전체가 히트), 틀 qf-pick__frame(4:3, --bg-media, img 는 object-fit: contain — 이미지 전체를 봐야 하므로 cover 가 아님), 왼쪽 아래 태그 qf-pick__tag(미디어 위 글래스, 짧은 글자), 한 줄 라벨 qf-pick__label(12px, 말줄임)을 둡니다. 상태: checked 는 틀 바깥 액센트 외곽선(2px, offset 2), focus-visible 은 --ring-focus, disabled 는 흐림, hover 는 --border-strong 외곽선. 변형: qf-pick__frame--none(점선 틀에 글자 하나, "없음"), qf-pick--muted(후보가 아닌 것 — 이미지 채도·밝기 낮춤 + 태그 경고색), qf-pick--current(지금 보이는 것 — 라벨 진하게). 줄은 qf-picks: 가로 스크롤 + scroll-snap, 안쪽 여백으로 외곽선·링이 잘리지 않고, 오른쪽 페이드는 qf-chips--scroll 과 같습니다(넘칠 때만, 끝에서 걷힘, 미지원은 is-end). 타일 폭 --sz-pick(160px, 390px 에서 2.1장).
.qf-picklayer: generic
Preview
<divclass="qf-picks"role="radiogroup"aria-label="Image to show"><labelclass="qf-pick qf-pick--current"><inputclass="qf-pick__input"type="radio"name="pick"value="1"checked><spanclass="qf-pick__frame"><imgsrc="brand-assets/png/og-image.png"alt=""><spanclass="qf-pick__tag">Shown</span></span><spanclass="qf-pick__label">Clien, photo</span></label><labelclass="qf-pick"><inputclass="qf-pick__input"type="radio"name="pick"value="2"><spanclass="qf-pick__frame"><imgsrc="brand-assets/png/icon-512.png"alt=""><spanclass="qf-pick__tag">AI</span></span><spanclass="qf-pick__label">AI image</span></label><labelclass="qf-pick qf-pick--muted"><inputclass="qf-pick__input"type="radio"name="pick"value="3"><spanclass="qf-pick__frame"><imgsrc="brand-assets/png/og-image.png"alt=""><spanclass="qf-pick__tag">Screenshot</span></span><spanclass="qf-pick__label">Ruliweb, screenshot of an article</span></label><labelclass="qf-pick"><inputclass="qf-pick__input"type="radio"name="pick"value="none"><spanclass="qf-pick__frame qf-pick__frame--none">None</span><spanclass="qf-pick__label">No image</span></label></div>
Wrap the row in role="radiogroup" with an aria-label; each tile is label > input[type=radio], so click, Space and arrow-key movement work natively (arrow focus scrolls the tile into view via scroll-padding). The radio's accessible name is the label text (tag + label); add a title or aria-describedby for more. Use alt="" for decorative thumbnails, a description when the content matters. The tag sits on an on-media glass (--on-media-glass-bg + --on-media-text), AA on any image; the muted tag uses --warn-400 on the strong glass (--on-media-glass-bg-strong): 6.8:1 even over a white image or the light letterbox (the .68 glass would be 4.1). Tiles are 160×120, an ample touch target, and the gap widens to --s-4 on touch devices. When the checked outline and the focus ring overlap they read as a 4px accent band — both are accent, so it reads as "the selected one is focused". A disabled tile only dims its image; the label stays readable in --text-disabled and the tile does not react to hover. Checked, focus and disabled styling rely on :has(), so browsers without it (Firefox < 121, Safari < 15.4) show no state.줄을 role="radiogroup" + aria-label 로 묶고 타일은 label > input[type=radio] 라 클릭·Space·화살표 이동이 네이티브로 동작합니다(화살표로 옮기면 scroll-padding 으로 타일이 줄 안에 들어옵니다). 라디오의 접근 가능한 이름은 label 의 텍스트(태그 + 라벨)이며, 설명이 더 필요하면 label 의 title 이나 aria-describedby 로. img 는 장식이면 alt="", 내용이 중요하면 설명. 태그는 미디어 위 글래스(--on-media-glass-bg + --on-media-text)라 어떤 이미지 위에서도 AA. muted 태그는 진한 글래스(--on-media-glass-bg-strong) 위 --warn-400 — 흰 이미지·라이트 레터박스 위에서도 6.8:1(.68 글래스는 4.1 로 미달). 타일 160×120 이라 터치 대상이 충분하고 터치 환경에서는 타일 간격이 --s-4 로 넓어집니다. checked 외곽선과 포커스 링이 겹치면 4px 액센트 띠로 보이며 둘 다 액센트라 "선택된 것에 포커스" 로 읽힙니다. disabled 타일은 이미지만 흐려지고 라벨은 --text-disabled 로 읽히며 hover 에 반응하지 않습니다. 선택·포커스·disabled 표시는 :has() 에 기대므로 미지원 브라우저(Firefox < 121, Safari < 15.4)에서는 상태가 보이지 않습니다.
Display & data
Avatar
A circular avatar that represents a user (with an optional status dot).사용자를 나타내는 원형 아바타입니다(상태 점은 옵션).
.qf-avatarlayer: generic
Preview
M
<spanclass="qf-avatar qf-avatar--md">
M
<spanclass="qf-avatar__status qf-avatar__status--online"></span></span>
Examples예시
M
Online
H
Idle
J
Do not disturb
S
Offline
Variants
M
qf-avatar--xs
M
qf-avatar--sm
M
qf-avatar--md
M
qf-avatar--lg
M
qf-avatar--xl
Parts & more: 구성 요소, 기타: qf-avatar__statusqf-avatar__status--onlineqf-avatar__status--idleqf-avatar__status--dndqf-avatar__status--offline
Provide meaningful alt text for the image, and do not convey the status dot by color alone, supplementing it with text or aria-label such as online or away.이미지에는 의미 있는 alt 를 제공하고, 상태 점은 색만으로 전하지 않도록 온라인, 자리 비움 등 텍스트나 aria-label 로 보충합니다.
Display & data
Badge
A small badge for a label, a status, or a notification count. Status tones: --success (healthy), --warn (resting, delayed), --danger (stopped, failed), --muted (paused, inactive). Marking AI-written text: put a default qf-badge with qf-i-sparkle reading "AI summary" in the kicker line above the title (neutral tone, 11px), and shorten the closing qf-notice--info to one line ("Tell us if something is wrong"). An svg inside a badge scales with the text (an explicit size modifier such as qf-icon--sm keeps its size).라벨, 상태, 알림 개수를 나타내는 작은 배지입니다. 상태는 --success(정상) --warn(쉬는 중, 지연) --danger(중단, 실패) --muted(멈춤, 비활성)로 구분합니다. AI 가 쓴 글의 표시: 제목 위 kicker 줄에 기본 qf-badge + qf-i-sparkle 로 "AI 요약" 을 두고(중립 톤, 11px), 글 끝의 qf-notice--info 는 "틀린 곳이 있으면 알려 주세요" 한 줄로 줄입니다. 배지 안 svg 는 글자 크기에 맞춰집니다(qf-icon--sm 같은 크기 변형을 명시하면 그 크기 유지).
.qf-badgelayer: generic
Preview
3
<spanclass="qf-badge qf-badge--count"aria-label="3 new notifications">3</span>
Examples예시
HealthyRestingStoppedPausedNeutral
Status set
3
Notification count (only)
Clien 22 posts
Neutral count (not red)
Politics4 communities · 9 posts · 9 min agoAI summary
Include text so meaning is not conveyed by color alone. qf-badge--count (red) is for notification counts only. Do not use it for neutral counts such as post or community totals; use the default qf-badge or qf-source__count (gray number) instead. Supplement count badges with an aria-label such as N unread.색만으로 의미를 전하지 않도록 텍스트를 함께 둡니다. qf-badge--count(빨강)는 알림 개수 전용입니다. 글 수, 커뮤니티 수 같은 중립 개수에는 쓰지 말고 기본 qf-badge 나 qf-source__count(회색 숫자)를 쓰세요. 개수 배지는 읽지 않음 N건 처럼 aria-label 로 보충합니다.
Display & data
CodeBlock
A code block that displays code in a monospace font.코드를 모노스페이스로 표시하는 코드 블록입니다.
.qf-codeblocklayer: generic
Preview
tsconst a = 1;
<preclass="qf-codeblock"><spanclass="qf-codeblock__lang">ts</span><code>const a = 1;</code></pre>
Variants
tsconst a = 1;
qf-codeblock--with-header
Parts & more: 구성 요소, 기타: qf-codeblock__langqf-codeblock__headerqf-codeblock__header-langqf-codeblock__copyqf-code-inline
Use a button element for the copy button and signal copy completion with 'Copied' text, not color alone. Wrap code in pre and code markup to convey its meaning.복사 버튼은 button 요소로 두고 복사 완료는 색만이 아니라 'Copied' 텍스트로 함께 알립니다. 코드는 pre, code 마크업으로 감싸 의미를 전달합니다.
Display & data
Prose
A body (prose) style that renders long-form documents such as Markdown in the design system's tone. The body measure defaults to a readable ~640px and is overridable via --qf-prose-max (e.g., none or var(--container-w-wide)). --article is for article bodies of several 3–6 sentence paragraphs (news write-ups): 16px body, one-line paragraph spacing (--s-6), and keep-all word breaking for Korean. Inside --article, h2/h3 are article subheadings (17px, 600, no underline, --s-6 above and --s-2 below) — when the body runs four paragraphs or more, put a short h2 (about 12 characters) where the thread changes.마크다운 등 장문 문서를 디자인 시스템 톤으로 렌더하는 본문(prose) 스타일입니다. 본문 폭은 기본 가독성 measure(약 640px)이며, --qf-prose-max 로 오버라이드합니다(예: none, var(--container-w-wide)). --article 은 뉴스 전말처럼 3~6문장 문단이 이어지는 기사 본문용으로 본문 16px, 문단 간격 한 줄(--s-6), 한국어 어절 유지(keep-all)를 적용합니다. --article 안의 h2/h3 는 기사 소제목(17px, 600, 밑선 없음, 위 --s-6 아래 --s-2)입니다 — 전말이 네 문단 이상이면 흐름이 바뀌는 곳에 12자 안의 h2 를 둡니다.
<articleclass="qf-prose"><h2>Document title</h2><p>
The body uses
<strong>emphasis</strong>
, a
<ahref="#prose">link</a>
, and
<code>inline</code>
code.
</p><ul><li>First item</li><li>Second item</li></ul><blockquote>Blockquotes are highlighted with the accent bar.</blockquote></article>
Examples예시
The Supreme Court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate, and issued a formal apology. The admission followed a week of reporting that traced dozens of receipts to restaurants closed on the dates listed.
Community reaction spread quickly across several Korean forums. Threads on Clien and Bobaedream questioned why the internal audit had taken years, while posters on 82cook focused on the apology itself.
The court said it would publish a corrected ledger and refer the matter to an outside review. No timeline was given.
Maintain the semantic HTML hierarchy (h1→h6 order, ul/ol/blockquote/table structure), and underline links to provide a cue beyond color. Keep body contrast at AA, and use token colors for code and tables.시맨틱 HTML 계층(h1→h6 순서, ul/ol/blockquote/table 구조)을 유지하고, 링크는 밑줄로 색 외 단서를 함께 줍니다. 본문 대비 AA, 코드/표는 토큰 색을 사용합니다.
Display & data
Lede
A lede (standfirst) paragraph under the title. A two-to-three-sentence summary set one step larger than body text (18px, so the line pitch widens too) in a secondary tone (--text-secondary), apart from the article body (qf-prose--article, 16px). --rule draws a short accent line underneath to mark where the body begins. Use --rule when nothing sits between lede and body; use the plain form when a picture separates them. Margins: --s-2 above, --s-6 below (inside a qf-stack the stack gap is added on both sides). Same measure as qf-prose; when overriding --qf-prose-max, set it on a common ancestor of lede and body.제목 아래 리드(standfirst) 문단입니다. 2~3문장 요약을 본문보다 한 단계 큰 글자(18px, 줄 간격도 따라 넓어짐)와 보조 톤(--text-secondary)으로 두어 본문(qf-prose--article, 16px)과 구분합니다. --rule 은 아래에 짧은 액센트 선을 그려 본문의 시작을 알립니다. 리드와 본문 사이에 그림이 없으면 --rule 을 쓰고, 그림이 사이를 가르면 기본형을 씁니다. 위 여백 --s-2, 아래 여백 --s-6(qf-stack 안에서는 stack 의 gap 이 양쪽에 더해집니다). 폭은 qf-prose 와 같은 measure 이며, --qf-prose-max 를 바꿀 때는 리드와 본문의 공통 조상에 둡니다.
The court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate and issued a formal apology, after a week of reporting traced dozens of receipts to restaurants closed on the dates listed.
The admission followed an investigation by a nonprofit newsroom. Community reaction spread quickly across several Korean forums, with threads questioning why the internal audit had taken years.
The court said it would publish a corrected ledger and refer the matter to an outside review. No timeline was given.
<article><h1class="qf-page-header__title">Supreme Court admits chief justice filed false expense reports</h1><pclass="qf-lede qf-lede--rule">The court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate and issued a formal apology, after a week of reporting traced dozens of receipts to restaurants closed on the dates listed.</p><sectionclass="qf-prose qf-prose--article"><p>The admission followed an investigation by a nonprofit newsroom. Community reaction spread quickly across several Korean forums, with threads questioning why the internal audit had taken years.</p><p>The court said it would publish a corrected ledger and refer the matter to an outside review. No timeline was given.</p></section></article>
The court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate and issued a formal apology, after a week of reporting traced dozens of receipts to restaurants closed on the dates listed.
The admission followed an investigation by a nonprofit newsroom. Community reaction spread quickly across several Korean forums, with threads questioning why the internal audit had taken years.
The court said it would publish a corrected ledger and refer the matter to an outside review. No timeline was given.
Use a p so it is read as the paragraph right after the heading (h1). Two cues separate it from the body independently of color: size (18 vs 16px) and the --rule line; the secondary tone is an extra cue (its contrast against body text is only 1.3–1.5:1). So when no picture sits between lede and body, always use --rule. The line is ::after decoration (drawn as a border so it survives forced-colors mode) and is not exposed to assistive technology. Weight is fixed at 400 (in Korean fallback fonts 500 may render like 400, so weight is not a reliable cue). Contrast: --text-secondary on --bg-app 10.7:1 (dark) / 10.2:1 (light); the --accent line 4.49 / 4.07.p 로 두어 제목(h1) 바로 다음 문단으로 낭독되게 합니다. 본문과의 구분은 크기(18 vs 16px)와 --rule 의 선, 두 가지가 색과 무관한 단서이고 보조 톤은 덧붙는 단서입니다(본문색과의 대비는 1.3~1.5:1 로 약함). 그래서 리드와 본문 사이에 그림이 없으면 반드시 --rule 을 씁니다. 선은 ::after 장식(border 로 그려 강제 색상 모드에서도 남음)이라 보조기기에 노출되지 않습니다. 굵기는 400 으로 고정합니다(한국어 폴백 글꼴에서 500 은 400 과 같게 렌더될 수 있어 단서가 되지 못함). 대비: --text-secondary on --bg-app 10.7:1(다크) / 10.2:1(라이트), 선 --accent 4.49 / 4.07.
Display & data
KeyPoints
An article's key points. A box placed between the lede and the body (after the picture if there is one), holding a label ("Key points", 12px caps tone) and two to four one-sentence items (under about 40 characters). Bullets are short accent bars, not dots (order carries no meaning, so no numbers). It has a --bg-panel background and a border but no left rule, so it does not read as a qf-notice. When it is the lede's immediate next sibling under the same parent, the qf-lede--rule line hides automatically (:has adjacent sibling); if the lede is wrapped in another element this does not fire, so leave --rule off then. Place the box outside qf-prose (inside, qf-prose's h2 style would override the label). Same measure as qf-prose.기사의 핵심 묶음입니다. 리드와 전말 사이(그림이 있으면 그림 다음)에 두는 상자로, 라벨("핵심", 12px 대문자 톤)과 한 문장짜리 항목 2~4개(40자 안)를 담습니다. 글머리는 점이 아니라 액센트의 짧은 막대(순서가 의미가 아니라 번호를 쓰지 않습니다). 바탕 --bg-panel 과 테두리만 있고 왼쪽 선이 없어 qf-notice 와 같은 종류로 보이지 않습니다. 리드와 같은 부모의 바로 다음 형제로 오면 qf-lede--rule 의 선이 자동으로 숨습니다(:has 인접 형제). 리드가 다른 요소에 감싸여 있으면 발동하지 않으니 그때는 --rule 을 붙이지 마세요. 상자는 qf-prose 밖에 둡니다(안에 두면 qf-prose 의 h2 스타일이 라벨을 덮습니다). 폭은 qf-prose 와 같은 measure 입니다.
.qf-keypointslayer: generic
Preview
Key points
The court admitted its expense reports were inaccurate and apologized.
Dozens of receipts named restaurants closed on the dates listed.
A corrected ledger and an outside review were promised, with no timeline.
<sectionclass="qf-keypoints"aria-labelledby="kp-title"><h2class="qf-keypoints__title"id="kp-title">Key points</h2><ulclass="qf-keypoints__list"><liclass="qf-keypoints__item">The court admitted its expense reports were inaccurate and apologized.</li><liclass="qf-keypoints__item">Dozens of receipts named restaurants closed on the dates listed.</li><liclass="qf-keypoints__item">A corrected ledger and an outside review were promised, with no timeline.</li></ul></section>
Examples예시
The court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate and issued a formal apology.
Key points
The court admitted its expense reports were inaccurate and apologized.
A corrected ledger and an outside review were promised.
What the reporting found
The admission followed an investigation by a nonprofit newsroom that traced dozens of receipts to restaurants closed on the dates listed.
Community reaction
Threads on several Korean forums questioned why the internal audit had taken years.
Use section[aria-labelledby] to name the region and make the label an h2 so "Key points" enters the document outline, and mark items up as ul/li (the bar is ::before decoration). Bar --accent on --bg-panel 3.97 dark / 3.79 light (graphics 3:1). Text --text on --bg-panel passes AA. More than four items makes the box heavier than the lede — keep it to four.section[aria-labelledby] 로 영역 이름을 주고 라벨을 h2 로 두어 "핵심" 이 문서 구조에 들어가게 하고, 항목은 ul/li 로 둡니다(막대는 ::before 장식). 막대 --accent on --bg-panel 다크 3.97 / 라이트 3.79(그래픽 3:1). 글자 --text on --bg-panel AA. 항목이 다섯 개를 넘으면 상자가 리드보다 무거워집니다 — 네 개까지.
Display & data
Mark
Search-term highlight. Use <mark class="qf-mark"> inside titles (qf-story__title) and summaries (qf-story__summary). Background is the subtle accent (--accent-subtle); the text color is inherited, so it stays calm in both 600-weight titles and 400-weight summaries. The 2px side padding is offset by a negative margin so text does not shift, and when it spans two lines each end is rounded (box-decoration-break: clone).검색어 강조입니다. <mark class="qf-mark"> 로 제목(qf-story__title)과 요약(qf-story__summary) 안에서 씁니다. 바탕은 액센트의 옅은 톤(--accent-subtle), 글자색은 상속이라 제목(600)과 요약(400) 어디서도 과하지 않습니다. 좌우 2px 패딩은 음수 margin 으로 상쇄되어 글자 흐름이 밀리지 않고, 두 줄에 걸치면 양 끝이 각각 둥급니다(box-decoration-break: clone).
The court acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate.
<articleclass="qf-story"><divclass="qf-story__kicker"><spanclass="qf-eyebrow">Politics</span><span>4 communities · 9 posts</span></div><h2class="qf-story__title">
Supreme
<markclass="qf-mark">Court</mark>
admits chief justice filed false expense reports
</h2><pclass="qf-story__summary">
The
<markclass="qf-mark">court</mark>
acknowledged on Tuesday that expense reports filed by its chief justice were inaccurate.
</p></article>
Variants
No variants — single style.변형 없음 — 단일 스타일.
Required tokens
--accent-subtle--r-xs--s-1
Accessibility
A mark element, which assistive technology may announce as highlighted (some do not). Inherited text color: --text-strong on --accent-subtle 13.1:1 dark / 14.6:1 light, --text-secondary 8.2 / 8.2 — AA. Use it only for matched search terms so the highlight does not change meaning. When a card hover turns the title accent-colored, text inside the mark stays --text-strong (accent text would be 4.25:1 in light). Because of the negative margin, a mark at the start of a line may lose its left 2px inside qf-clamp (overflow hidden) — only the decorative end flattens.mark 요소라 보조기기가 강조로 알립니다(일부는 낭독하지 않음). 글자색 상속: --text-strong on --accent-subtle 다크 13.1:1 / 라이트 14.6:1, --text-secondary 8.2 / 8.2 — AA. 강조가 의미를 바꾸지 않도록 검색어 외에는 쓰지 않습니다. 카드 hover 로 제목이 accent 색이 되어도 mark 안 글자는 --text-strong 을 유지합니다(라이트에서 accent 글자는 4.25:1). 음수 margin 때문에 줄 첫머리의 mark 는 왼쪽 2px 이 qf-clamp(overflow hidden) 안에서 잘릴 수 있습니다 — 장식 끝만 평평해집니다.
Display & data
Footnotes
A Markdown footnotes list — footnotes and back-reference links below a divider at the end of the body. In-body reference superscripts (sup>a) are accented via --accent-text within qf-prose.마크다운 각주 목록 — 본문 하단 구분선 아래 각주와 역참조 링크입니다. 본문 내 참조 위첨자(sup>a)는 qf-prose 스코프에서 --accent-text 로 강조됩니다.
<sectionclass="qf-footnotes"><ol><liid="fn1">
디자인 시스템은 사람과 AI가 함께 씁니다.
<aclass="qf-footnotes__backref"href="#fnref1"aria-label="본문으로 돌아가기">↩</a></li></ol></section>
Footnotes use an ol to convey order, and back-reference links carry an aria-label (e.g., back to content) so meaning is not carried by an icon or glyph alone. In-body references are real a[href] anchors enabling round-trip navigation.각주는 ol 로 순서를 전달하고, 역참조 링크에는 aria-label(예: 본문으로 돌아가기)을 두어 아이콘, 기호 단독 의존을 피합니다. 본문 참조는 실제 a[href] 앵커로 왕복 이동이 가능합니다.
Display & data
Transclude
A transclusion card that quotes another note inline within the body, with a left --border-strong accent, --bg-panel surface, and a __source link to the original at the top. Named qf-transclude to avoid colliding with the chat embed qf-embed.다른 노트를 본문에 인라인 인용하는 트랜스클루전 카드입니다. 좌측 --border-strong 액센트 + --bg-panel 배경, 상단 __source 원문 링크. 채팅 임베드 qf-embed 와 이름 충돌을 피해 qf-transclude 로 명명했습니다.
Embedded content from another note is quoted inline here.
<blockquoteclass="qf-transclude"><divclass="qf-transclude__source"><svgclass="qf-icon qf-icon--sm"aria-hidden="true"><usehref="#qf-i-link"/></svg><ahref="/notes/api">notes/api</a></div><p>Embedded content from another note is quoted inline here.</p></blockquote>
Convey the quotation with blockquote semantics, and provide a real a[href] source link for navigation to the origin. The left accent is decorative, with source text supplying context.인용 의미를 blockquote 시맨틱으로 전달하고, 원문 링크는 실제 a[href] 로 출처 이동을 보장합니다. 좌측 액센트는 장식이며 출처 텍스트로 맥락을 함께 제공합니다.
Display & data
EmptyState
An empty-state area that provides guidance when there is no content. Pages such as a 404 are built from the same parts: title, body, a search form (qf-search), and an action button as children (no variant needed).내용이 없을 때 안내하는 빈 상태 영역입니다. 404 같은 안내 화면도 제목, 본문, 찾기 입력(qf-search), 행동 버튼을 자식으로 두면 됩니다(변형 불필요).
.qf-emptylayer: generic
Preview
No items yet
Add your first item to get started.
<divclass="qf-empty"><svgclass="qf-icon qf-icon--xl"aria-hidden="true"style="color:var(--text-muted)"><usehref="#qf-i-inbox"/></svg><divclass="qf-empty__title">No items yet</div><divclass="qf-empty__body">Add your first item to get started.</div><buttonclass="qf-btn qf-btn--primary qf-btn--sm">New item</button></div>
Examples예시
Page not found
The address may be wrong, or the issue may have been removed.
Convey the guidance through title and body text rather than the icon. When it appears dynamically, placing it in an aria-live region is recommended.안내 의미를 아이콘이 아닌 제목, 본문 텍스트로 전달합니다. 동적으로 나타날 때는 aria-live 영역에 넣는 것을 권장합니다.
Display & data
Skeleton
A placeholder skeleton shown while content is loading.콘텐츠 로딩 중에 보여 주는 자리표시자 스켈레톤입니다.
Mark the loading area with aria-busy="true" to tell screen readers it is not meaningful content. Respecting prefers-reduced-motion for motion-sensitive users is recommended.로딩 영역을 aria-busy="true"로 표시하고 의미 있는 콘텐츠가 아님을 화면 낭독기에 알립니다. 모션 민감 사용자를 위해 prefers-reduced-motion을 존중하는 것을 권장합니다.
Display & data
Eyebrow
A small uppercase label placed above a section.섹션 위에 올리는 작은 대문자 레이블입니다.
.qf-eyebrowlayer: generic
Preview
New feature
<spanclass="qf-eyebrow">New feature</span>
Variants
No variants — single style.변형 없음 — 단일 스타일.
Required tokens
--fs-12--font-sans--tracking-caps--accent-text
Accessibility
The uppercase transform is visual presentation only, so keep the actual text in normal casing so screen readers read it correctly. Do not carry meaning in the accent color alone.대문자 변환은 시각 표현이며 실제 텍스트는 정상 표기로 두어 화면 낭독기가 올바르게 읽도록 합니다. 강조 색에만 의미를 싣지 않습니다.
Display & data
KeyboardShortcutSheet
A sheet that presents a list of keyboard shortcuts grouped by category.단축키 목록을 그룹별로 보여 주는 시트입니다.
Mark each keycap with a kbd element to convey its meaning, and manage focus within the dialog context when placed inside a modal.각 키캡은 kbd 요소로 표기해 의미를 전달하고 모달 안에 둘 때는 dialog 컨텍스트에서 포커스를 관리합니다.
Display & data
Card
A surface container that groups content (with header, body, and footer slots).콘텐츠를 묶는 표면 컨테이너입니다(헤더, 본문, 푸터 슬롯).
.qf-cardlayer: generic
Preview
Title
This is the content.
<sectionclass="qf-card"><divclass="qf-card__header"><h3class="qf-card__title">Title</h3></div><divclass="qf-card__body">This is the content.</div></section>
Variants
Title
This is the content.
qf-card--interactive
Parts & more: 구성 요소, 기타: qf-card__headerqf-card__titleqf-card__bodyqf-card__footer
An interactive card (--interactive) should be wrapped in a keyboard-accessible element (a/button) or given an appropriate role and tabindex, with visible focus.상호작용 카드(--interactive)는 키보드 접근 가능한 요소(a/button)로 감싸거나 적절한 role 과 tabindex 를 부여하고 포커스를 보이게 합니다.
Display & data
Tag
A chip that represents a label or category (a text label, distinct from Badge which is used for counts and status). As <a class="qf-tag"> it becomes a clickable tag (hover = selected surface; 40px tall with a 44px hit area on touch). Show counts such as post totals with qf-tag__count (a lighter-weight number) — qf-badge--count (red) is for notifications only. It stays clickable inside a qf-story--stretched card.라벨이나 카테고리를 나타내는 칩입니다(카운트, 상태용 Badge 와 구분되는 텍스트 라벨). <a class="qf-tag"> 로 두면 눌리는 태그가 됩니다(hover 는 selected 표면, 터치 환경 40px + 44px 히트). 글 수 같은 개수는 qf-tag__count(가는 숫자)로 — qf-badge--count(빨강)는 알림 전용입니다. qf-story--stretched 카드 안에서도 눌립니다.
Give the remove button (qf-tag__remove) an aria-label (e.g., Remove design tag). Pair label text with color so meaning is never conveyed by color alone. A link tag is an a[href] with a visible focus ring; supplement a count with an aria-label such as "powershell, 24 posts". Do not put qf-tag__remove inside a link tag (a button inside an a). Inline tags inside qf-prose keep the line height and do not grow on touch. The count uses --text-secondary at weight 400 (tag text is 500): 9.5 / 9.5 on --bg-hover and still AA on the --bg-selected hover surface (--text-muted would be 4.48 in light, so it is not used).제거 버튼(qf-tag__remove)에는 aria-label(예: 디자인 태그 제거)을 둡니다. 색만으로 의미를 전하지 않고 라벨 텍스트를 함께 둡니다. 링크 태그는 a[href] 라 포커스 링이 보이고, 개수는 숫자 뒤에 단위를 aria-label 로 보충할 수 있습니다(예: "powershell, 글 24건"). 링크 태그에는 qf-tag__remove 를 넣지 않습니다(a 안의 button). 본문(qf-prose) 안 인라인 태그는 줄 높이를 지키며 터치 성장이 없습니다. 개수는 --text-secondary(굵기 400, 태그 글자는 500)라 바탕 --bg-hover 위 9.5 / 9.5, hover 표면 --bg-selected 위에서도 AA 입니다(--text-muted 는 라이트 4.48 로 미달이라 쓰지 않음).
Display & data
Stat
Displays a dashboard metric (KPI) with a large value, a label, and a trend delta. A hint line under the value (qf-stat__hint, e.g. "limit 300") is optional. --sm is for short figures in an aside or summary row (value 18px 600, label 12px).대시보드 지표(KPI)를 큰 값, 라벨, 추세 델타로 표시합니다. 값 아래 보조 텍스트(qf-stat__hint, 예: 상한 300장)를 둘 수 있습니다. --sm 은 사이드·요약 줄의 짧은 숫자(값 18px 600, 라벨 12px)입니다.
.qf-statlayer: generic
Preview
Monthly active users12,840▲ 8.2%
<divclass="qf-stat"><spanclass="qf-stat__label">Monthly active users</span><spanclass="qf-stat__value">12,840</span><spanclass="qf-stat__delta qf-stat__delta--up">▲ 8.2%</span></div>
Examples예시
Monthly active users12,840▲ 8.2%
Increase
Churn rate3.1%▼ 1.4%
Decrease
Pending tasks27
No delta
Images kept212limit 300
With hint
Variants
Monthly active users12,840▲ 8.2%
qf-stat--sm
Parts & more: 구성 요소, 기타: qf-stat__labelqf-stat__valueqf-stat__deltaqf-stat__delta--upqf-stat__delta--downqf-stat__hint
Trend is conveyed not just by color but with an arrow/sign (▲▼ or +/-) and text, avoiding reliance on color alone. Pair the value with its unit and meaning.추세는 색뿐 아니라 화살표/부호(▲▼ 또는 +/-)와 텍스트로 전달해 색 단독 의존을 피합니다. 값에는 단위/의미를 함께 둡니다.
Display & data
Sparkline
A mini chart that shows a time-series trend within a small area. The consumer generates points/path from the data, and the DS provides token-based styling (line and area colors).시계열 추세를 작은 영역에 보여주는 미니 차트입니다. 데이터→points/path 는 소비처가 생성하고 DS 는 토큰 기반 스타일(선, 영역 색)을 제공합니다.
Parts & more: 구성 요소, 기타: qf-sparkline__lineqf-sparkline__area
Required tokens
--accent--ok-400--warn-400--danger-400
Accessibility
Unless decorative, provide a trend summary via role=img + aria-label (e.g., "Throughput over the last 24 hours, rising"), and pair color with numeric labels.장식이 아니면 role=img + aria-label 로 추세 요약(예: "최근 24시간 처리량, 상승")을 제공하고, 색뿐 아니라 수치 라벨을 함께 둡니다.
Display & data
Table
A table that presents data in rows and columns, offering a sort caret (aria-sort), a sticky header, row selection, and toolbar affordances (the consumer handles sort and selection logic).행과 열로 데이터를 보여주는 표입니다. 정렬 캐럿(aria-sort), sticky 헤더, 행 선택, 툴바 affordance 를 제공합니다(정렬/선택 로직은 소비처).
Convey header relationships with a thead/th(scope=col)/tbody structure, and describe the table's purpose with a caption or aria-label. At narrow widths, qf-table-wrap enables horizontal scrolling.thead/th(scope=col)/tbody 구조로 헤더 관계를 전달하고, 표 용도는 caption 또는 aria-label 로 설명합니다. 좁은 폭은 qf-table-wrap 으로 가로 스크롤합니다.
Display & data
DescriptionList
A list that presents term-and-description (key-value) pairs in an aligned layout.용어와 설명(키-값) 쌍을 정렬해 보여주는 목록입니다.
Convey key-value relationships with dl/dt/dd semantics. The grid handles the visual two-column alignment while the markup preserves the meaning.dl/dt/dd 시맨틱으로 키-값 관계를 전달합니다. 시각적 2열 정렬은 grid 가 담당하고 의미는 마크업이 보존합니다.
Display & data
AvatarGroup
Stacks multiple avatars in an overlapping cluster to compactly represent a set of participants.여러 아바타를 겹쳐 쌓아 참여자를 압축 표시합니다.
Provide alt text (the user's name) on each avatar image, and supplement the group's overall meaning (e.g. "5 participants") with aria-label. The ring is separated from the surface via --avatar-ring (surface).각 아바타 이미지에 alt(사용자명)를 제공하고, 그룹 전체 의미(예: 참여자 5명)는 aria-label 로 보충합니다. ring 은 --avatar-ring(표면) 으로 표면과 분리됩니다.
Display & data
List
A general-purpose vertical list with dividers (settings rows, item lists).구분선이 있는 범용 세로 목록입니다(설정 행, 항목 리스트).
Build it with ul/li, and make interactive items (--interactive) an a/button to preserve keyboard access and visible focus. Interactive rows are at least 40px tall, and a link or button inside (.qf-list__text) extends its tap target into the row padding (about 37px, WCAG 2.5.8). Inline content inside the link (icon + text, qf-clamp) keeps flowing as usual.ul/li 로 만들고, 상호작용 항목(--interactive)은 a/button 으로 두어 키보드 접근과 포커스 가시를 보존합니다. 상호작용 행은 최소 40px 이고, 행 안의 링크나 버튼(.qf-list__text)은 행 패딩까지 탭 대상으로 가져갑니다(약 37px, WCAG 2.5.8). 링크 안의 내용은 인라인 흐름 그대로 둘 수 있습니다(아이콘 + 텍스트, qf-clamp).
Display & data
RankList
A ranked list (e.g. trending issues 1–5). Numbers come from a CSS counter so there is no digit in the markup (rank carries meaning: accent, tabular-nums). Each item is a link (qf-ranklist__link) holding a title (qf-ranklist__title, 14px 600, two-line clamp) and a meta line (qf-ranklist__meta, 12px muted), with hover tint, visited tone and focus ring. Meant for the aside but works unchanged when the layout drops to one column.순위 목록입니다(지금 뜨는 이슈 1~5). 번호는 CSS counter 로 그려 마크업에 숫자가 없고(순위가 의미라 번호, 액센트, tabular-nums), 항목 전체가 링크(qf-ranklist__link)이며 제목(qf-ranklist__title, 14px 600, 두 줄 clamp)과 메타(qf-ranklist__meta, 12px muted)로 이루어집니다. hover 틴트, 방문 톤, 포커스 링. 사이드 열에서 쓰지만 1열로 내려가도 그대로 동작합니다.
Use ol/li, and add role="list" to the ol because list-style: none can drop list semantics in WebKit. The CSS counter number is ::before generated text, so it becomes part of the link name and is read as "1 title meta" (the rank is conveyed). For titles cut by the two-line clamp, provide the full text via title or aria-label. Number --accent-text on --bg-app 7.5 / 5.3 — AA.ol/li 로 두되 list-style: none 이라 WebKit 에서 목록 의미가 떨어질 수 있으니 ol 에 role="list" 를 둡니다. CSS counter 번호는 ::before 생성 텍스트라 링크 이름에 포함되어 "1 제목 메타" 로 읽힙니다(순위가 전달됨). 두 줄 clamp 로 잘린 제목은 title 속성이나 aria-label 로 전체를 줄 수 있습니다. 번호 --accent-text on --bg-app 7.5 / 5.3 — AA.
Display & data
Story
One item of a content list such as news, issues, or a blog. It fixes the hierarchy of kicker (category + meta), title, summary, source chips, and a 4:3 thumbnail. The whole item may be the link (a.qf-story) or only the title. --pictured places text in column 1 and the thumbnail in column 2 (on narrow screens it only shrinks, it does not move); --lead emphasizes the first item (24px title, wider thumbnail; on narrow screens a 16:9 thumbnail sits above the text); --compact shows only kicker and title (summary and sources are hidden even if present). Visited items get a quieter title. Place the list inside qf-container--reading (720px): narrow overflows titles and source chips, the default width makes summary lines too long. Source chips inside an item are automatically one step smaller (11px). --skeleton is a placeholder card shown while the next page loads (bars in the empty slots, same height as a real card; if real cards are --stretched, add --stretched to the skeleton too so the sources row matches on touch devices). --stretched stretches the title link over the whole card when the card is an article with only the title linked, so source chips (qf-source--link) and tag links (a.qf-tag) inside can be real links — sources use qf-source, categories and topics use qf-tag.뉴스, 이슈, 블로그 같은 콘텐츠 목록의 한 항목입니다. 분류와 메타(kicker), 제목, 요약, 출처 칩, 4:3 썸네일의 위계를 구성요소로 고정합니다. 항목 전체가 링크(a.qf-story)이거나 제목만 링크일 수 있습니다. --pictured 는 텍스트 1열 + 썸네일 2열(좁은 폭에서는 크기만 줄고 자리는 유지), --lead 는 첫 항목 강조(제목 24px, 썸네일 확대. 좁은 폭에서는 16:9 썸네일이 텍스트 위로), --compact 는 제목과 kicker 만(요약, 출처는 마크업이 있어도 숨김). 방문한 항목은 제목이 한 톤 낮아집니다. 목록은 qf-container--reading(720px) 안에 두는 것을 권합니다(narrow 는 제목과 출처 칩이 넘치고 기본 폭은 요약 행이 깁니다). 항목 안의 출처 칩은 자동으로 한 단계 작아집니다(11px). --skeleton 은 다음 화면을 불러오는 동안 자리를 지키는 카드(빈 슬롯에 막대, 실제 카드와 같은 높이. 실제 카드가 --stretched 면 스켈레톤에도 --stretched 를 붙여 터치 환경의 출처 행 높이를 맞춥니다). --stretched 는 카드가 article 이고 제목만 링크일 때 제목 링크를 카드 전체로 늘려, 카드 안의 출처 칩(qf-source--link)과 태그 링크(a.qf-tag)를 눌리는 링크로 둘 수 있게 합니다 — 출처는 qf-source, 분류·주제는 qf-tag.
<aclass="qf-story qf-story--pictured"href="#story"><imgclass="qf-story__media"src="brand-assets/png/og-image.png"alt=""width="180"height="135"><divclass="qf-story__kicker"><spanclass="qf-eyebrow">Politics</span><span>4 communities · 9 posts · 9 min ago</span></div><h2class="qf-story__title">Supreme Court admits chief justice filed false expense reports, apologizes</h2><pclass="qf-story__summary qf-clamp qf-clamp--3">Reporting by an investigative outlet traced dozens of receipts to restaurants that were closed on the dates listed. The court issued a formal apology and said a corrected ledger would follow.</p><divclass="qf-sources qf-story__sources"><spanclass="qf-source">82cook</span><spanclass="qf-source">Inven</span><spanclass="qf-source">Clien</span><spanclass="qf-source">Bobaedream</span></div></a>
Use h2/h3 for the title to convey list structure. When the whole item is a link, do not nest other links inside it (no source --link chips). Give decorative thumbnails alt="" and width/height to avoid layout shift. Focus is shown as a ring around the whole item. The visited tone is a secondary cue; meaning never relies on color alone. When the whole item is a link, the kicker, title, summary, and sources all become the link name and it gets long; if summaries are long, consider linking only the title (see the Text only example). To shorten the link name to the title only, aria-labelledby="<title id>" can be set on a.qf-story. With --stretched, text inside the card cannot be selected by dragging and the context menu is the title link's — in return the link name is just the title. Give skeletons aria-hidden="true" and replace them wholesale when real cards arrive.제목은 h2/h3 로 두어 목록의 문서 구조를 전달합니다. 항목 전체를 링크로 만들 때는 안에 다른 링크(출처 칩 --link 등)를 넣지 않습니다(중첩 링크 금지). 장식 썸네일은 alt="" 로 두고 width/height 를 적어 레이아웃 점프를 막습니다. 포커스는 항목 전체에 링으로 보입니다. 방문 톤은 보조 단서일 뿐 의미를 색에만 싣지 않습니다. 항목 전체가 링크면 kicker, 제목, 요약, 출처가 모두 링크 이름이 되어 길어집니다. 요약이 길면 제목만 링크로 두는 형태(Text only 예제)를 고려하세요. 링크 이름을 제목만으로 줄이려면 a.qf-story 에 aria-labelledby="제목 id" 를 둘 수 있습니다. --stretched 에서는 카드 안 텍스트를 드래그로 선택할 수 없고 우클릭 메뉴가 제목 링크의 것입니다 — 그 대신 링크 이름이 제목만으로 짧습니다. 스켈레톤은 aria-hidden="true" 로 두고 실제 카드가 오면 통째로 바꿉니다.
Display & data
Source
A small, neutral chip naming one source (a community or outlet). An outline pill, distinct from Tag (labels) and Badge (status, notifications). qf-source__count shows a count as a gray number (instead of a red count badge); qf-source__mark holds an initial or favicon. --link makes it a link to the original list; qf-sources is the wrapping group container. Inside qf-story__sources and qf-timeline__body they are secondary information and shrink automatically by one step (11px, matching the body line height).출처(커뮤니티, 매체) 이름 하나를 나타내는 중립 톤의 작은 칩입니다. 태그(라벨)나 배지(상태, 알림)와 구분되는 outline pill 입니다. qf-source__count 는 회색 숫자로 개수를(빨간 count 배지 대신), qf-source__mark 는 이니셜이나 파비콘을 넣습니다. --link 는 눌러서 원문 목록으로 가는 링크형, qf-sources 는 줄바꿈되는 묶음 컨테이너입니다. qf-story__sources 와 qf-timeline__body 안에서는 보조 정보라 자동으로 한 단계 작아집니다(11px, 본문 줄 높이와 같음).
Counts are gray numbers, so they do not read as warnings; add an aria-label when needed (e.g. "2 posts on Bobaedream"). --link is an anchor with a visible focus ring. On touch devices (any-pointer: coarse, including touch laptops) only --link chips grow to 44px; static chips and chips inside a linked qf-story stay as they are. Do not use --link inside a qf-story that is itself a link.개수는 회색 숫자라 경고로 읽히지 않습니다. 필요하면 aria-label 로 뜻을 보충합니다(예: 보배드림 글 2건). --link 는 a 로 두고 포커스 링이 보입니다. 터치 환경(any-pointer: coarse, 터치 노트북 포함)에서는 --link 칩만 44px 로 커지고, 정적 칩과 카드 안 칩은 그대로입니다. 항목 전체가 링크인 qf-story 안에서는 --link 를 쓰지 않습니다.
Display & data
DayRule
A date or section rule placed between list items: an eyebrow-toned label plus a line, used as an li (with role="separator", also provide the label via aria-label). --sticky pins it to the top while scrolling and paints the app background (--bg-app) so items do not show through. Knobs: --qf-dayrule-top (offset under a fixed header, default 0; the rule sits at --z-sticky, so with a fixed header you must set this to the header height, e.g. var(--h-navbar)) and --qf-dayrule-bg (background when used inside a panel). Give items a scroll-margin-top so a sticky rule does not cover the top of a focused item. When a sticky top bar (qf-navbar--sticky) hides with is-hidden, the rule automatically moves up to top: 0.목록 사이에 끼우는 날짜, 구간 구분줄입니다. eyebrow 톤 라벨과 선으로 이루어지며 li 로 씁니다(role="separator" 를 쓰면 aria-label 로 라벨을 함께 줍니다). --sticky 는 스크롤 시 상단에 붙고 앱 배경(--bg-app)을 깔아 아래 항목이 비치지 않습니다. 노브: --qf-dayrule-top(고정 헤더 아래 오프셋, 기본 0. z-index 가 --z-sticky 라 고정 헤더가 있으면 반드시 헤더 높이, 예: var(--h-navbar), 를 지정), --qf-dayrule-bg(패널 안에서 쓸 때 배경). sticky 구분줄이 포커스된 항목의 윗부분을 가리지 않게 항목에 scroll-margin-top 을 주는 것을 권합니다. 고정 상단 바(qf-navbar--sticky)가 is-hidden 으로 숨으면 날짜줄은 자동으로 맨 위(top: 0)로 올라붙습니다.
In ARIA, separator has presentational children, so text inside it is not exposed to assistive technology. If you use role="separator", always duplicate the label in aria-label (e.g. aria-label="Today, Wednesday, Sep 30"); if counting it among the items is acceptable, use a plain li without the role so the label is read as-is. Keep the label as real text; the uppercase transform is visual only. The --sticky background must stay opaque so text does not show through; do not set a translucent value.ARIA 의 separator 는 자식 요소가 presentational 이라 안의 텍스트가 보조기기에 노출되지 않습니다. role="separator" 를 쓰려면 같은 텍스트를 aria-label 로 반드시 함께 두고(예: aria-label="오늘, 9월 30일 수요일"), 항목 수에 섞여도 괜찮으면 role 없이 일반 li 로 두어 라벨이 그대로 낭독되게 합니다. 라벨은 실제 텍스트로 두고 대문자 변환은 시각 표현입니다. --sticky 의 배경은 아래 텍스트가 겹쳐 보이지 않게 불투명해야 하므로 반투명 값을 넣지 않습니다.
Display & data
Timeline
A vertical timeline of events in time order (unlike qf-steps, which shows progress through stages). Each item has a time (qf-timeline__time), a marker (qf-timeline__marker), and a body (qf-timeline__body: source chip + title link + meta); qf-timeline__day marks a date change. The marker color is exposed through one custom property, --qf-timeline-marker, which consumers set with a token (e.g. var(--viz-2)) to tell sources apart (default --text-muted). The time column (--sz-timeline-time) survives narrow widths; for very narrow layouts, --stacked moves the time above the body.시간순 기록을 세로로 보여 주는 타임라인입니다(진행 단계를 나타내는 qf-steps 와 다릅니다). 항목은 시각(qf-timeline__time), 마커(qf-timeline__marker), 본문(qf-timeline__body: 출처 칩 + 제목 링크 + 메타)로 이루어지고, 날짜가 바뀌는 곳에 qf-timeline__day 를 둡니다. 마커 색은 커스텀 프로퍼티 --qf-timeline-marker 하나로 열어 두어 소비처가 토큰(예: var(--viz-2))으로 출처를 구분합니다(기본 --text-muted). 좁은 폭에서도 시각 칸(--sz-timeline-time)이 유지되며, 더 좁게 써야 하면 --stacked 로 시각을 본문 위로 올립니다.
<olclass="qf-timeline"><liclass="qf-timeline__day">Sep 30</li><liclass="qf-timeline__item"style="--qf-timeline-marker: var(--viz-1)"><timeclass="qf-timeline__time"datetime="2026-09-30T09:12">09:12</time><spanclass="qf-timeline__marker"aria-hidden="true"></span><divclass="qf-timeline__body"><spanclass="qf-source">Clien</span><aclass="qf-link"href="#post">The chief justice's expense reports do not add up</a><spanclass="qf-timeline__meta">4 comments</span></div></li><liclass="qf-timeline__item"style="--qf-timeline-marker: var(--viz-2)"><timeclass="qf-timeline__time"datetime="2026-09-30T09:40">09:40</time><spanclass="qf-timeline__marker"aria-hidden="true"></span><divclass="qf-timeline__body"><spanclass="qf-source">82cook</span><aclass="qf-link"href="#post">So the Supreme Court apologized. Now what?</a><spanclass="qf-timeline__meta">31 comments</span></div></li><liclass="qf-timeline__item"style="--qf-timeline-marker: var(--viz-3)"><timeclass="qf-timeline__time"datetime="2026-09-30T11:05">11:05</time><spanclass="qf-timeline__marker"aria-hidden="true"></span><divclass="qf-timeline__body"><spanclass="qf-source">Bobaedream</span><aclass="qf-link"href="#post">Court to publish a corrected ledger, refers case to outside review</a><spanclass="qf-timeline__meta">12 comments</span></div></li><liclass="qf-timeline__day">Sep 29</li><liclass="qf-timeline__item"><timeclass="qf-timeline__time"datetime="2026-09-29T22:48">22:48</time><spanclass="qf-timeline__marker"aria-hidden="true"></span><divclass="qf-timeline__body"><spanclass="qf-source">Inven</span><aclass="qf-link"href="#post">First report surfaces on the expense records</a><spanclass="qf-timeline__meta">2 comments</span></div></li></ol>
Convey order with an ol and mark times with time[datetime]. Markers are decorative (aria-hidden); the source is conveyed by the qf-source text, not by color. Titles are qf-link anchors with a visible focus ring and a light underline so they read as links next to the meta text on the same line, and visited links are toned down. Date dividers (qf-timeline__day) are read as list item text.ol 로 순서를 전달하고 시각은 time[datetime] 으로 둡니다. 마커는 장식(aria-hidden)이며 출처는 색이 아니라 qf-source 텍스트로 전달합니다. 제목은 qf-link 로 두어 포커스 링이 보이고, 같은 줄의 메타 텍스트와 구분되게 옅은 밑줄로 링크 단서를 함께 줍니다. 방문한 링크는 한 톤 낮아집니다. 날짜 구분(qf-timeline__day)은 li 텍스트로 낭독됩니다.
Display & data
Clamp
A utility that truncates text to N lines with an ellipsis — keeps card titles and descriptions uniform.텍스트를 N줄에서 말줄임하는 유틸리티입니다. 카드 제목, 설명을 균일하게 자릅니다.
.qf-clamplayer: generic
Preview
This is a longer description that clamps to two lines with an ellipsis when it overflows its container width, keeping cards uniform.
<pclass="qf-clamp"style="max-width:320px;margin:0">This is a longer description that clamps to two lines with an ellipsis when it overflows its container width, keeping cards uniform.</p>
Examples예시
This variant clamps to three lines instead of two. Useful for denser cards where a little more context fits before the ellipsis truncates the remaining overflow text.
3 lines (--3)
A single-line clamp behaves like a truncating ellipsis on overflow.
1 line (--1)
Variants
This is a longer description that clamps to two lines with an ellipsis when it overflows its container width, keeping cards uniform.
qf-clamp--1
This is a longer description that clamps to two lines with an ellipsis when it overflows its container width, keeping cards uniform.
qf-clamp--3
This is a longer description that clamps to two lines with an ellipsis when it overflows its container width, keeping cards uniform.
qf-clamp--reserve
Required tokens
--lh-snug
Accessibility
Visual truncation only — the full text stays in the accessibility tree (never aria-hidden the clamp node). When text may be cut, pair it with a title attribute or qf-tooltip.시각적 절단만이며 전체 텍스트는 접근성 트리에 유지합니다(클램프 노드에 aria-hidden 금지). 잘릴 수 있으면 title 이나 qf-tooltip 을 함께 제공합니다.
Display & data
SortToggle
A three-state sort toggle that cycles ascending↔descending↔off — used as a table header (th[aria-sort]) or a button, with a direction glyph.오름차순↔내림차순↔off를 순환하는 3상태 정렬 토글입니다. 테이블 헤더(th[aria-sort]) 또는 버튼으로 쓰며 방향을 글리프로 표시합니다.
.qf-sort-togglelayer: generic
Preview
<buttonclass="qf-sort-toggle is-active"type="button"data-direction="asc"aria-label="Sort by name, ascending"><span>Name</span><spanclass="qf-sort-toggle__indicator"aria-hidden="true">▲</span></button>
Examples예시
Descending (active)
Off (inactive)
Variants
qf-sort-toggle--lg
Parts & more: 구성 요소, 기타: qf-sort-toggle__indicator
Table headers use th[aria-sort='ascending|descending|none']; standalone buttons use role=button with an accessible name. Cycle with Enter/Space, convey direction via aria-sort/glyph (not color alone), and keep headers at a 44px tap target.테이블 헤더는 th[aria-sort='ascending|descending|none'], 독립 버튼은 role=button + 접근명입니다. Enter/Space로 순환하고 방향은 색이 아니라 aria-sort/글리프로 전달하며 헤더는 44px 탭 타깃을 유지합니다.
Charts & data viz
Chart
A multi-series time-series line/area chart. The consumer computes coordinates (points/path) and tick values from the data (same contract as Sparkline); the DS provides token-based styling for axes, grid, series, hover guide, and value tooltip. Set series color on the parent group via style="color:var(--viz-N)" (1–8).멀티시리즈 시계열 라인/영역 차트입니다. 좌표(points/path)와 눈금 값은 소비처가 데이터에서 계산하고(sparkline 과 동일 계약), DS 는 축, 그리드, 시리즈, 호버 가이드, 값 툴팁의 토큰 기반 스타일을 제공합니다. 시리즈 색은 부모 그룹에 style="color:var(--viz-N)"(1~8) 로 지정합니다.
Summarize the trend with role="img" + aria-label on the svg (e.g., "Downloads vs failures over the last 24h, rising"). The hover guide/tooltip is a pointer affordance; pair color with a legend and numeric labels to avoid color-only reliance. Offer an equivalent data table for keyboard/screen-reader users.svg 에 role="img" + aria-label 로 추세를 요약합니다(예: "최근 24시간 다운로드 대 실패, 상승"). 호버 가이드/툴팁은 포인터 보조 수단이며, 색 단독 의존을 피하도록 범례와 수치 라벨을 함께 둡니다. 키보드/스크린리더 사용자에게는 동일 데이터의 표 대체본 제공을 권장합니다.
Charts & data viz
BarChart
A grouped or stacked bar chart. The consumer computes bar coordinates/heights for a category axis (site/category) plus values. Groups place bars side by side; stacks pile them at the same x (both expressed via coordinates). Use --horizontal to switch label alignment for horizontal bars. Set bar color via style="color:var(--viz-N)".그룹 또는 스택 막대 차트입니다. 카테고리축(사이트/카테고리) + 값, 막대 좌표/높이는 소비처가 계산합니다. 그룹은 막대를 나란히, 스택은 같은 x 에 쌓아 배치합니다(둘 다 좌표로 표현). --horizontal 로 가로 막대 레이블 정렬을 전환합니다. 막대 색은 style="color:var(--viz-N)".
.qf-barchartlayer: generic
Preview
<divclass="qf-barchart"style="--chart-h:200px"><svgclass="qf-barchart__svg"viewBox="0 0 320 200"role="img"aria-label="Downloaded vs failed by site, grouped"><gclass="qf-barchart__grid"><linex1="40"y1="40"x2="312"y2="40"></line><linex1="40"y1="100"x2="312"y2="100"></line><linex1="40"y1="160"x2="312"y2="160"></line></g><lineclass="qf-barchart__axis"x1="40"y1="20"x2="40"y2="160"></line><lineclass="qf-barchart__axis"x1="40"y1="160"x2="312"y2="160"></line><rectclass="qf-barchart__bar"x="60"y="56"width="22"height="104"style="color:var(--viz-1)"></rect><rectclass="qf-barchart__bar"x="86"y="132"width="22"height="28"style="color:var(--viz-7)"></rect><rectclass="qf-barchart__bar"x="150"y="40"width="22"height="120"style="color:var(--viz-1)"></rect><rectclass="qf-barchart__bar"x="176"y="120"width="22"height="40"style="color:var(--viz-7)"></rect><rectclass="qf-barchart__bar"x="240"y="84"width="22"height="76"style="color:var(--viz-1)"></rect><rectclass="qf-barchart__bar"x="266"y="146"width="22"height="14"style="color:var(--viz-7)"></rect><textclass="qf-barchart__label"x="84"y="178">api</text><textclass="qf-barchart__label"x="174"y="178">cdn</text><textclass="qf-barchart__label"x="264"y="178">web</text></svg></div>
Provide a comparison summary via role="img" + aria-label, and include value-label text so the chart does not rely on color alone. Reinforce the category×series breakdown with a legend.svg 에 role="img" + aria-label 로 비교 요약을 제공하고, 값 레이블 텍스트를 함께 둬 색 단독 의존을 피합니다. 카테고리×시리즈 분해는 범례로 보강합니다.
Charts & data viz
Donut
A multi-segment donut chart (an N-segment distribution, unlike the single-gauge Radial). Each segment is expressed with stroke-dasharray/stroke-dashoffset against the circle circumference, with lengths computed by the consumer. Place a total/label in the center and reinforce the distribution with a legend. Set segment color via style="color:var(--viz-N)".다세그먼트 도넛 차트입니다(단일 게이지인 Radial 과 달리 N 세그먼트 분포). 각 세그먼트는 원 둘레 기준 stroke-dasharray/stroke-dashoffset 로 표현하며 길이는 소비처가 계산합니다. 중앙에 합계/라벨을 두고 분포는 범례로 보강합니다. 세그먼트 색은 style="color:var(--viz-N)".
State the segment proportions with role="img" + aria-label on the svg (e.g., "Failure reasons: timeout 60%, auth 28%, other 12%"). Pair the centered total text and a legend to avoid color-only reliance.svg 에 role="img" + aria-label 로 세그먼트 비율을 명시합니다(예: "실패 사유: 타임아웃 60%, 인증 28%, 기타 12%"). 중앙 합계 텍스트와 범례로 색 단독 의존을 피합니다.
Charts & data viz
Heatmap
A site×time or site×category density heatmap (throughput/failures). Cells are a CSS grid; pass per-cell intensity via inline style --qf-heat (0–1) and the color interpolates between --heat-empty and currentColor. The consumer sets the column count (grid-template-columns) and cell values. Set color via style="color:var(--viz-N)".사이트×시간 또는 사이트×카테고리 밀도(처리량/실패) 히트맵입니다. CSS 그리드 셀로, 강도는 셀마다 --qf-heat(0~1) 를 인라인 style 로 전달하면 색이 --heat-empty 와 currentColor 사이를 보간합니다. 그리드 열 수(grid-template-columns)와 셀 값은 소비처가 지정합니다. 색은 style="color:var(--viz-N)".
Because this is a grid (not an svg), give the container role="img" + aria-label summarizing what the density represents, and provide the exact value per cell via title (or aria-label) so it does not rely on color/brightness alone.svg 가 아닌 그리드이므로 컨테이너에 role="img" + aria-label 로 무엇의 밀도인지 요약하고, 각 셀에는 title(또는 aria-label)로 정확한 수치를 제공해 색/명도 단독 의존을 피합니다.
Charts & data viz
Legend
A legend shared by the charts (color swatch + label + optional value). Match the swatch to the series color via style="color:var(--viz-N)". The --toggle variant turns items into button[aria-pressed] to convey series show/hide state.차트들이 공유하는 범례입니다(색칩 + 라벨 + 선택적 수치). 색칩은 style="color:var(--viz-N)" 로 시리즈 색과 맞춥니다. --toggle 변형은 항목을 button[aria-pressed] 로 만들어 시리즈 표시 on/off 를 전달합니다.
Use ul/li for the non-toggle form. For the toggle form, make each item a button + aria-pressed (true/false) so screen readers announce the visibility state, and ensure dimmed items are distinguished by state (aria-pressed), not color alone.비토글형은 ul/li 로 의미를 전달합니다. 토글형은 각 항목을 button + aria-pressed(true/false) 로 만들어 표시 상태를 스크린리더에 알리고, 흐려진 항목도 색 외 상태(aria-pressed)로 구분되게 합니다.
Media
MediaCard
A thumbnail card with an aspect-ratio-locked media slot (letterbox) plus overlay badges and toggles — for video, image, and poster grids.종횡비 고정 미디어 슬롯(레터박스)에 오버레이 배지, 토글을 얹는 썸네일 카드입니다. 비디오, 이미지, 포스터 그리드에 씁니다.
.qf-media-cardlayer: generic
Preview
12:34
Sunset over the harbor, extended cut
1080p248 MB2 days ago
<divclass="qf-media-card qf-media-card--interactive"style="max-width:260px"><divclass="qf-media-card__media"><divclass="qf-media-card__overlay qf-media-card__overlay--start"><spanclass="qf-badge">12:34</span></div><divclass="qf-media-card__overlay qf-media-card__overlay--end"><buttonclass="qf-btn qf-btn--icon qf-btn--ghost"aria-label="Favorite"aria-pressed="false"><svgclass="qf-icon qf-icon--md"aria-hidden="true"><usehref="#qf-i-star"/></svg></button></div></div><divclass="qf-media-card__body"><divclass="qf-media-card__title qf-clamp">Sunset over the harbor, extended cut</div><divclass="qf-media-card__meta"><span>1080p</span><span>248 MB</span><span>2 days ago</span></div></div></div>
Make activatable media slots operable with role=button, tabindex=0, Enter/Space, and aria-label. Overlay toggles are real buttons with aria-pressed and a 44px target; badge text keeps 4.5:1 over the scrim; skeletons set aria-busy; truncated titles carry a title attribute.활성화 가능한 미디어 슬롯은 role=button, tabindex=0, Enter/Space, aria-label 로 동작을 전달합니다. 오버레이 토글은 실제 button + aria-pressed + 44px, 배지 텍스트는 스크림 위에서 4.5:1, 스켈레톤은 aria-busy, 잘린 제목은 title 속성을 둡니다.
Media
Figure
A picture (or video) with a one-line caption below. The caption is 13px in a secondary tone; a link inside is underlined and carries a qf-i-external icon so it reads as a link beyond color. Non-link notes such as "Image: AI generated" sit in the same place without an icon. Limit the image height with --qf-figure-max-h (none by default).그림(또는 영상)과 그 아래 한 줄 캡션입니다. 캡션은 13px 보조 톤이고, 안의 링크는 밑줄과 qf-i-external 아이콘으로 링크임이 색 외에도 드러납니다. "이미지 출처: AI 생성" 같은 비링크 문구도 같은 자리에 아이콘 없이 둡니다. 그림 최대 높이는 --qf-figure-max-h 로 제한할 수 있습니다(기본 없음).
Use figure/figcaption so image and caption are associated, and give the img an alt that describes the content (caption = source, alt = content). External links use target=_blank with rel=noopener, the icon is aria-hidden, and opening in a new window is conveyed in the link text or aria-label. Caption links are inline text links, so only vertical padding is added to help tapping.figure/figcaption 으로 두어 그림과 설명이 묶이게 하고, img 에는 내용을 설명하는 alt 를 둡니다(캡션은 출처, alt 는 내용). 외부 링크는 target=_blank 와 rel=noopener 를 쓰고 아이콘은 aria-hidden, 새 창 열림은 링크 텍스트나 aria-label 로 알립니다. 캡션 링크는 본문 안 인라인 링크라 세로 패딩만 더해 탭을 돕습니다.
Media
MediaOverlay
Glass control and status chrome that floats over a video or image stage. Stays light regardless of theme, avoids the safe area, and passes pointer events through so it never blocks native controls.영상이나 이미지 스테이지 위에 떠서 컨트롤과 상태를 보여주는 글래스 크롬입니다. 테마와 무관하게 항상 밝고, safe-area를 피하며, pointer-events 패스스루로 네이티브 컨트롤을 가리지 않습니다.
__pill--button is a real button with a focus ring visible over video and a 44px target. __hud uses role=status + aria-live=polite while buffering and role=alert on error. The container's pointer-events:none must not trap focus or block keyboard access to native controls.__pill--button은 실제 button + 영상 위에서 보이는 포커스 링 + 44px 입니다. __hud는 버퍼링 시 role=status, aria-live=polite, 에러 시 role=alert 를 둡니다. 컨테이너 pointer-events:none이 포커스를 가두거나 네이티브 컨트롤 키보드 접근을 막지 않아야 합니다.
Feedback & status
Toast
A notification message that appears briefly in a corner of the screen. --brief shows briefly and fades out (--dur-toast-brief, 2.4 s; under reduced motion it simply disappears after 2.4 s without motion. No live disappearing example is kept in the catalog). Pattern: a share button (qf-btn--ghost qf-btn--icon + qf-i-share) calls navigator.share, or falls back to copying the link and showing a qf-toast--brief "Link copied".화면 모서리에 잠깐 뜨는 알림 메시지입니다. --brief 는 짧게 떠 있다 사라집니다(--dur-toast-brief, 2.4초. 축소 모션에서는 모션 없이 2.4초 뒤 사라짐. 카탈로그에는 사라지는 라이브 예제를 두지 않습니다). 패턴: 공유 버튼(qf-btn--ghost qf-btn--icon + qf-i-share)은 navigator.share 를 쓰고, 없으면 링크를 복사한 뒤 qf-toast--brief 로 "링크를 복사했습니다" 를 띄웁니다.
Announce with role="status" and aria-live="polite", and use role="alert" for errors. Include title and body text so meaning is not conveyed by the left color bar alone. Remove a --brief toast on animationend, and give the toast region role="status" (aria-live=polite) so it is announced.role="status" 와 aria-live="polite" 로 알리고 오류는 role="alert" 를 씁니다. 좌측 색 막대만으로 의미를 전하지 않도록 제목과 본문 텍스트를 함께 둡니다. --brief 는 animationend 에서 요소를 제거하고, 토스트 영역을 role="status"(aria-live=polite) 로 두어 낭독되게 합니다.
Feedback & status
ToastRegion
A fixed container that stacks multiple qf-toast elements, defaulting to the top right and repositionable with --bottom/--left.여러 qf-toast 를 쌓아 올리는 고정 컨테이너입니다. 기본 우상단, --bottom/--left 로 위치를 바꿉니다.
Set aria-live=polite (assertive for urgent) on the region so screen readers announce toasts as they are added. Apply pointer-events to the toasts only.region 에 aria-live=polite(긴급은 assertive)를 두어 추가되는 토스트를 스크린리더가 읽게 합니다. pointer-events 는 토스트에만.
Feedback & status
Callout
Obsidian-style callouts — 13 typed notice blocks rendered inside qf-prose body, with optional collapsing via details/summary.Obsidian 스타일 콜아웃 — qf-prose 본문 안에 렌더하는 13종 안내 블록입니다. 접기(details/summary)를 지원합니다.
.qf-calloutlayer: generic
Preview
Tip
Use tokens and dark, light adapt automatically.
<divclass="qf-callout qf-callout--tip"><divclass="qf-callout__title"><spanclass="qf-callout__icon"><svgclass="qf-icon qf-icon--sm"aria-hidden="true"><usehref="#qf-i-sparkle"/></svg></span>
Tip
</div><divclass="qf-callout__body">Use tokens and dark, light adapt automatically.</div></div>
Examples예시
Note
A general note in body flow.
note
Abstract
A short summary of what follows.
abstract
Info
Contextual information.
info
Todo
Something still to do.
todo
Tip
Use tokens and dark, light adapt automatically.
tip
Success
The step completed.
success
Question
Is this the right approach?
question
Warning
Double-check before continuing.
warning
Failure
The check did not pass.
failure
Danger
This action cannot be undone.
danger
Bug
Known issue, tracked in #142.
bug
Example
A worked example follows.
example
Quote
Design is how it works.
quote
Collapsible
Click the summary to fold and unfold.
collapsible (details/summary)
Variants
Tip
Use tokens and dark, light adapt automatically.
qf-callout--note
Tip
Use tokens and dark, light adapt automatically.
qf-callout--abstract
Tip
Use tokens and dark, light adapt automatically.
qf-callout--info
Tip
Use tokens and dark, light adapt automatically.
qf-callout--todo
Tip
Use tokens and dark, light adapt automatically.
qf-callout--tip
Tip
Use tokens and dark, light adapt automatically.
qf-callout--success
Tip
Use tokens and dark, light adapt automatically.
qf-callout--question
Tip
Use tokens and dark, light adapt automatically.
qf-callout--warning
Tip
Use tokens and dark, light adapt automatically.
qf-callout--failure
Tip
Use tokens and dark, light adapt automatically.
qf-callout--danger
Tip
Use tokens and dark, light adapt automatically.
qf-callout--bug
Tip
Use tokens and dark, light adapt automatically.
qf-callout--example
Tip
Use tokens and dark, light adapt automatically.
qf-callout--quote
Parts & more: 구성 요소, 기타: qf-callout__titleqf-callout__iconqf-callout__body
Convey the type via the title text in addition to the left accent bar and icon color, avoiding reliance on color alone (WCAG 1.4.1). Icons are aria-hidden; collapsing uses native details/summary to preserve keyboard and screen reader behavior, with a focus ring on the summary.타입 의미를 좌측 강조선과 아이콘 색뿐 아니라 제목 텍스트로 함께 전달해 색 단독 의존을 피합니다(WCAG 1.4.1). 아이콘은 aria-hidden, 접기는 네이티브 details/summary 로 키보드, 스크린리더 동작을 보존하고 summary 에 포커스 링을 둡니다.
Feedback & status
Banner
A banner that displays a notice at the top of the page or inline.상단 또는 본문에 알림을 표시하는 배너입니다.
.qf-bannerlayer: generic
Preview
Your connection is unstable.
<divclass="qf-banner qf-banner--warn"role="status"><spanclass="qf-banner__msg">Your connection is unstable.</span><buttonclass="qf-banner__close"aria-label="Close">×</button></div>
Variants
Your connection is unstable.
qf-banner--info
Your connection is unstable.
qf-banner--warn
Your connection is unstable.
qf-banner--danger
Your connection is unstable.
qf-banner--accent
Parts & more: 구성 요소, 기타: qf-banner__iconqf-banner__msgqf-banner__actionsqf-banner__close
Assign role=status or role=alert to match its nature, and convey the informational meaning with an icon and text, not color alone. Give the close button an aria-label.성격에 맞춰 role=status 또는 role=alert를 부여하고 정보 의미를 색뿐 아니라 아이콘과 텍스트로 전달합니다. 닫기 버튼에는 aria-label을 둡니다.
Feedback & status
Notice
An inline message box that surfaces info, warning, or danger states.정보, 경고, 위험을 알리는 인라인 안내 박스입니다.
.qf-noticelayer: generic
Preview
Caution
You have unsaved changes.
<divclass="qf-notice qf-notice--warn"role="alert"><spanclass="qf-notice__icon"><svgclass="qf-icon qf-icon--md"aria-hidden="true"><usehref="#qf-i-alert"/></svg></span><divclass="qf-notice__body"><pclass="qf-notice__title">Caution</p>
You have unsaved changes.
</div></div>
Examples예시
Could not load more issues.
Load failed + retry (end of an infinite list)
Variants
Caution
You have unsaved changes.
qf-notice--info
Caution
You have unsaved changes.
qf-notice--warn
Caution
You have unsaved changes.
qf-notice--danger
Parts & more: 구성 요소, 기타: qf-notice__iconqf-notice__bodyqf-notice__title
Meaning is carried by a title and body text in addition to the left border color and icon, avoiding reliance on color alone. Warning and danger use role=alert, while info uses role=status to announce to screen readers.좌측 보더 색과 아이콘에 더해 제목, 본문 텍스트로 의미를 전달해 색 단독 의존을 피합니다. 경고, 위험은 role=alert로, 정보는 role=status로 스크린리더에 알립니다.
Feedback & status
Spinner
A spinning loader that indicates work is in progress.작업이 진행 중임을 나타내는 회전 로더입니다.
Announce progress with role=status and an aria-label (e.g., Loading). prefers-reduced-motion is honored by the global guard in tokens.css.role=status 와 aria-label(예: 불러오는 중)로 진행을 알립니다. prefers-reduced-motion 은 tokens.css 전역 가드가 존중합니다.
Feedback & status
Progress
Displays task progress as a bar.작업 진행률을 막대로 표시합니다.
Convey the value with role=progressbar and aria-valuenow/valuemin/valuemax. Express an indeterminate state with aria-busy=true or by omitting the value attributes.role=progressbar 와 aria-valuenow/valuemin/valuemax 로 값을 전달합니다. 진행률 미정 상태는 aria-busy=true 또는 값 속성 생략으로 표현합니다.
Feedback & status
Radial
Shows a single value such as capacity or utilization as a radial gauge. Pass --qf-radial-value (0–100) via inline style.용량, 사용률 등 단일 값을 방사형(게이지)으로 보여줍니다. --qf-radial-value(0~100) 를 인라인 style 로 전달합니다.
Convey the value with role=progressbar + aria-valuenow/min/max, and use the centered numeric text to avoid reliance on color alone.role=progressbar + aria-valuenow/min/max 로 값을 전달하고, 중앙 수치 텍스트로 색 단독 의존을 피합니다.
Feedback & status
Nudge
A pill button floating centered under the top bar that says something like "3 new issues" and, when pressed, scrolls to the top and refreshes. The consumer inserts it only when there is something new (short slide-down mount motion) and removes it on press or when handled — no state classes. If the top bar is not --h-navbar tall, set --qf-nudge-top. 44px on phones. It may be a button or an a (no underline).상단 바 아래 가운데에 떠서 "새 이슈 3건" 처럼 알리고, 누르면 맨 위로 가며 새로 고치는 알약 버튼입니다. 새 항목이 있을 때만 소비처가 DOM 에 넣고(위에서 내려오는 짧은 마운트 모션), 누르거나 처리되면 제거합니다 — 상태 클래스가 없습니다. 상단 바 높이가 기본(--h-navbar)과 다르면 --qf-nudge-top 으로 맞춥니다. 폰에서는 44px. button 또는 a 로 쓸 수 있습니다(밑줄 없음).
.qf-nudgelayer: generic
Preview
<divstyle="position:relative;height:88px"><buttonclass="qf-nudge"type="button"style="position:absolute;top:var(--s-3)"><svgclass="qf-icon qf-icon--sm"aria-hidden="true"><usehref="#qf-i-chevron-up"/></svg>
3 new issues
</button></div>
A button whose text is its name (icon aria-hidden). Place it inside an aria-live=polite region so its appearance is announced. White text on the solid accent passes AA. The mount motion is disabled under prefers-reduced-motion.button 이며 문구 자체가 이름입니다(아이콘은 aria-hidden). 새로 나타났음을 알리려면 aria-live=polite 영역 안에 넣습니다. 흰 글자는 solid accent 위에서 AA 를 넘습니다. 마운트 모션은 prefers-reduced-motion 에서 꺼집니다.
Feedback & status
Steps
Displays the progress steps of a multi-step flow.다단계 흐름의 진행 단계를 표시합니다.
Convey order with an ol and set aria-current="step" on the current step. Communicate the completed/current state with marker numbers and text, not color alone.ol 로 순서를 전달하고 현재 단계에 aria-current=step 을 둡니다. 완료/현재 상태를 색뿐 아니라 마커 숫자, 텍스트로 함께 전달합니다.
Feedback & status
TypingDots
A three-dot staggered bounce that signals 'generating' or 'typing' — semantically distinct from a spinner (working) or progress (quantified).standalone 3점 staggered bounce로 '생성 중'/입력 중을 표시합니다. spinner(작업 중), progress(정량)와 의미가 다릅니다.
Give the root role=status, aria-live=polite, and an accessible name (e.g. aria-label='Generating'); the dots are aria-hidden. Under prefers-reduced-motion, replace the bounce with an opacity fade — never freeze it at scale(0).루트에 role=status, aria-live=polite, 접근명(예: aria-label='생성 중')을 두고 점은 aria-hidden 입니다. prefers-reduced-motion 에서 bounce를 opacity 페이드로 대체하고 scale(0)로 얼려 안 보이게 두지 않습니다.
Navigation
Menu
A dropdown menu that presents a list of actions.동작 목록을 보여주는 드롭다운 메뉴입니다.
Set role="menu" and role="menuitem", navigate with the up and down arrows, and close on Esc. Show shortcuts as text so meaning is not conveyed by color alone.role="menu" 와 role="menuitem" 을 지정하고, 위아래 화살표로 이동하며 Esc 로 닫습니다. 단축키는 텍스트로 함께 보여 색만으로 의미를 전하지 않습니다.
Navigation
Tabs
A set of tabs for switching between multiple views.여러 뷰를 전환하는 탭 모음입니다.
Set role="tablist" and role="tab", and mark the active tab with aria-selected="true". Navigate with the left and right arrows, and convey state with text in addition to the underline indicator.role="tablist" 과 role="tab" 을 지정하고 선택 탭은 aria-selected="true" 로 알립니다. 좌우 화살표로 이동하며 밑줄 표시 외에 상태를 텍스트로도 전합니다.
Navigation
TableOfContents
An 'on this page' table of contents that sticks to the right (qf-app-shell__aside) of a blog or doc page.블로그, 문서 우측(qf-app-shell__aside)에 sticky 로 붙는 '이 페이지에서' 목차입니다.
.qf-toclayer: generic
Preview
<navclass="qf-toc"aria-label="On this page"><divclass="qf-toc__title">On this page</div><ul><liclass="qf-toc__item"><aclass="qf-toc__link qf-toc__link--active"href="#intro">Introduction</a></li><liclass="qf-toc__item qf-toc__item--d2"><aclass="qf-toc__link"href="#setup">Setup</a></li><liclass="qf-toc__item qf-toc__item--d3"><aclass="qf-toc__link"href="#install">Install the CLI</a></li></ul></nav>
Give the nav an aria-label to convey the landmark, and mark the active item with a left vertical indicator (--accent) plus text emphasis so meaning is not carried by color alone. Links meet a 44px touch target and long titles are truncated with an ellipsis.nav 에 aria-label 을 두어 랜드마크 의미를 전달하고, 활성 항목은 좌측 세로 인디케이터(--accent) + 텍스트 강조로 색 단독 의존을 피합니다. 링크는 44px 터치 타깃을 확보하고 긴 제목은 말줄임합니다.
Navigation
Breadcrumb
A breadcrumb trail that shows the path to the current location.현재 위치까지의 경로를 보여주는 이동 경로 내비게이션입니다.
Build it as an ol inside nav[aria-label="breadcrumb"], and set aria-current="page" on the current page's item. Mark the separator (__sep) as decorative with aria-hidden.nav[aria-label=경로] 안의 ol 로 만들고, 현재 페이지 항목에 aria-current=page 를 둡니다. 구분 기호(__sep)는 aria-hidden 으로 장식 처리합니다.
Navigation
Pagination
Pagination controls for moving between pages.페이지 사이를 이동하는 페이지네이션입니다.
Wrap it in nav[aria-label="pagination"] and set aria-current="page" on the current page. Give the previous/next buttons an aria-label, and signal unavailable states with disabled.nav[aria-label=페이지] 로 감싸고 현재 페이지에 aria-current=page 를 둡니다. 이전/다음 버튼에는 aria-label 을 주고, 불가 상태는 disabled 로 알립니다.
Navigation
Navbar
A top app bar that holds branding, navigation links, and actions. --sticky pins the bar to the top; use it on long lists and reading pages where search and a way back up must stay reachable. Class contract: consumer JS toggles is-stuck when scrolled past 0 (shadow and line) and is-hidden while scrolling down (slides up out of view). Narrow-width contract: the bar stays one line — the brand truncates with an ellipsis, the link group (qf-navbar__nav) scrolls horizontally when it overflows, icon buttons never shrink, and gaps/padding step down at ≤600px. On phones keep to brand + two links + three icon buttons; move a select or long links into a drawer or menu on the consumer side (the DS hides nothing).브랜드, 내비 링크, 액션을 담는 상단 앱 바입니다. --sticky 는 위에 붙는 고정 상단 바입니다 — 긴 목록이나 읽기 페이지처럼 내려간 뒤에도 찾기와 맨 위로 가는 길이 필요할 때 씁니다. 클래스 계약: 소비처 JS 가 스크롤이 0 이 아니면 is-stuck(그림자·선), 아래로 스크롤 중이면 is-hidden(위로 숨음)을 붙였다 뗍니다. 좁은 폭 계약: 바는 한 줄을 지킵니다 — 브랜드는 말줄임, 링크 묶음(qf-navbar__nav)은 넘치면 가로 스크롤, 아이콘 버튼은 줄지 않음, ≤600px 에서 간격·여백 한 단계 축소. 폰에 둘 것은 브랜드 + 링크 2개 + 아이콘 버튼 3개까지이고 select·긴 링크는 소비처가 드로어나 메뉴로 옮깁니다(DS 는 아무것도 숨기지 않습니다).
Wrap it in header > nav[aria-label] and set aria-current="page" on the link for the current location. Use a[href] for links, with a visible keyboard focus. A theme toggle is a qf-btn--ghost qf-btn--icon with aria-pressed (light mode = true); consumer JS swaps the sun (qf-i-sun) / moon (qf-i-moon) icon. The pressed state shows as the selected surface. A pinned bar covers part of the viewport: place in-page sticky elements (qf-dayrule) below it with --qf-dayrule-top: var(--h-navbar) and give focus targets a scroll-margin-top. The hide transition becomes instant under prefers-reduced-motion. For --sticky, put the nav directly under body (or make the header itself the bar); a nav inside a header only sticks within the header box. If keyboard focus enters a hidden bar it reappears. Icon buttons inside the bar get a 44px hit area on touch devices automatically. If the brand is icon + text, put the ellipsis styling on the text span (an inline-flex brand needs text-overflow on the text element) and give the full name via title. __nav shows no overflow hint, so keep to two links on phones (keyboard focus scrolls automatically).header > nav[aria-label] 로 감싸고, 현재 위치 링크에 aria-current=page 를 둡니다. 링크는 a[href], 키보드 포커스 가시. 밝기 토글은 qf-btn--ghost qf-btn--icon 에 aria-pressed(밝은 모드 = true)를 두고 해(qf-i-sun)/달(qf-i-moon) 아이콘을 소비처 JS 가 바꿉니다. 눌린 상태는 selected 표면으로 보입니다. 고정 바는 뷰포트를 가리므로 페이지 안 sticky(qf-dayrule)는 --qf-dayrule-top: var(--h-navbar) 로 그 아래에 두고, 포커스 이동 대상에는 scroll-margin-top 을 줍니다. 숨김 전환은 prefers-reduced-motion 에서 즉시 바뀝니다. --sticky 는 nav 를 body 직하(또는 header 자체)에 두어야 뷰포트에 붙습니다(header 안의 nav 는 header 박스 안에서만 붙음). 숨은 바 안으로 키보드 포커스가 들어오면 다시 보입니다. 바 안의 아이콘 버튼은 터치 환경에서 44px 히트 영역을 자동으로 받습니다. 브랜드가 아이콘 + 글자면 글자 span 에 말줄임 스타일을 두고(inline-flex 브랜드는 text-overflow 가 글자 요소에 걸려야 함) title 로 전체 이름을 줍니다. __nav 는 넘침 단서가 없으므로 폰에서 링크 2개까지(키보드 포커스는 자동 스크롤).
Navigation
SideNav
A general-purpose vertical navigation organized into sections and items (unrelated to a chat channel list).섹션과 항목으로 구성된 범용 세로 내비게이션입니다(채팅 채널 목록과 무관).
Wrap it in nav[aria-label] and set aria-current="page" on the current item. Distinguish groups with section headings (qf-sidenav__section).nav[aria-label] 로 감싸고, 현재 항목에 aria-current=page 를 둡니다. 섹션 제목(qf-sidenav__section)으로 그룹을 구분합니다.
Navigation
PostNav
Previous / next post links at the end of an article (end of the reading column, before the footer — the "after reading" slot). Two cells; at ≤600px they stack so titles do not wrap into many lines. Each cell is a card-toned block link (qf-postnav__link, --prev / --next) holding an eyebrow (qf-postnav__eyebrow: "← Previous" / "Next →") and a title (qf-postnav__title, 15px 600, two-line clamp); the next cell is right-aligned. If only one neighbour exists, render just that cell.글 끝의 이전 글 / 다음 글입니다(읽기 열 끝, 바닥글 앞 — "읽은 다음"의 자리). 두 칸이며 ≤600px 에서는 한 칸씩 세로로 쌓여 제목이 여러 줄로 감기지 않습니다. 각 칸은 카드 톤의 블록 링크(qf-postnav__link, --prev / --next)로 머리말(qf-postnav__eyebrow: "← 이전 글" / "다음 글 →")과 제목(qf-postnav__title, 15px 600, 두 줄 clamp)을 담고, 다음 글은 오른쪽 정렬입니다. 한쪽만 있으면 그 칸만 둡니다.
.qf-postnavlayer: generic
Preview
<navclass="qf-postnav"aria-label="Adjacent posts"><aclass="qf-postnav__link qf-postnav__link--prev"href="#prev"><spanclass="qf-postnav__eyebrow">← Previous</span><spanclass="qf-postnav__title">.NET - WPF JumpList</span></a><aclass="qf-postnav__link qf-postnav__link--next"href="#next"><spanclass="qf-postnav__eyebrow">Next →</span><spanclass="qf-postnav__title">PowerShell - Creating a Credential for remote access</span></a></nav>
Wrap in nav[aria-label="Adjacent posts"]; each cell is an a[href]. The eyebrow arrows are text and are read, so the link name reads like "Previous post, title". The focus ring surrounds the whole cell. Provide clamped titles in full via a title attribute.nav[aria-label="앞뒤 글"] 로 감싸고 각 칸은 a[href] 입니다. 머리말의 화살표는 텍스트라 낭독되며 링크 이름은 "이전 글 제목" 처럼 읽힙니다. 포커스 링이 칸 전체에 보입니다. 두 줄 clamp 로 잘린 제목은 title 속성으로 전체를 줄 수 있습니다.
Navigation
Chip
Desktop filter chips and their group (qf-chips). Works as links (a + aria-current="page") or buttons (button + aria-pressed="true"); the selected state uses an accent-subtle background, accent border, and a bold label. The group wraps by default; --scroll makes a single horizontally scrolling row on narrow screens (scrollbar hidden). Shares tokens with the mobile qf-m-filter-chip (--r-pill, --accent-subtle, --accent) for visual consistency; only the label color is --accent-on-subtle for AA. --scroll fades its right edge into the background to hint there is more, only when the row overflows, and the fade clears at the end (automatically where scroll-driven animations are supported; otherwise consumer JS adds is-end). On touch devices chips are 40px tall with a transparent 44px hit area. qf-picks (image pick rows) shares the same fade.데스크톱 필터 칩과 그 묶음(qf-chips)입니다. 링크(a + aria-current="page")와 버튼(button + aria-pressed="true") 모두 지원하며 선택 상태는 accent-subtle 배경, accent 테두리, 굵은 라벨로 표시합니다. 기본은 줄바꿈(wrap), --scroll 은 좁은 폭에서 한 줄 가로 스크롤(스크롤바 숨김)입니다. 모바일 qf-m-filter-chip 과 같은 토큰(--r-pill, --accent-subtle, --accent)을 써서 시각이 일관되며, 라벨 색만 AA 를 위해 --accent-on-subtle 입니다. --scroll 은 오른쪽 끝을 배경으로 녹아들게 페이드해 더 있음을 암시하고, 넘칠 때만 생기며 끝까지 스크롤하면 걷힙니다(스크롤 타임라인 지원 브라우저는 자동, 그 밖은 소비처 JS 가 is-end 를 붙임). 터치 환경에서 칩은 40px 이고 투명 영역으로 44px 히트를 확보합니다. 같은 페이드를 qf-picks(이미지 선택 타일 줄)도 씁니다.
Link chips are anchors inside nav[aria-label] with aria-current="page" on the current one; button chips use aria-pressed. The selected state is conveyed by border and weight as well as color. The focus ring stays visible (--scroll keeps a 4px inner padding for the halo and a matching negative margin to stay aligned, so the parent needs at least 4px of horizontal room), and on touch devices (any-pointer: coarse, including touch laptops) chips are 40px tall with a transparent 44px hit area (hit areas of adjacent rows touch but do not overlap). In --scroll, tabbing brings each chip into view. The --scroll fade appears only when the row overflows (with scroll-driven animation support), and tabbing to a chip stops left of the fade via scroll-padding. Without support, consumer JS adds is-end on load, resize and scroll when the row is at its end or does not overflow.링크 칩은 nav[aria-label] 안의 a 로 두고 현재 항목에 aria-current="page" 를, 버튼 칩은 aria-pressed 를 씁니다. 선택 상태는 색과 함께 테두리와 굵기로도 전달합니다. 포커스 링이 보이고(--scroll 은 halo 까지 보이도록 4px 여백을 안쪽에 두고 같은 크기의 음수 margin 으로 정렬을 유지하므로, 부모에 4px 이상 좌우 여백이 필요합니다), 터치 환경(any-pointer: coarse, 터치 노트북 포함)에서는 칩이 40px 이고 투명 영역으로 44px 히트를 확보합니다(인접 행의 히트 영역은 맞닿기만 함). --scroll 은 키보드로 Tab 이동 시 브라우저가 칩을 뷰로 스크롤합니다. --scroll 의 페이드는 넘칠 때만 생기고(스크롤 타임라인 지원 시), Tab 으로 칩에 가면 scroll-padding 으로 페이드 왼쪽에 멈춥니다. 미지원 브라우저는 소비처 JS 가 load·resize·scroll 에서 끝에 닿았거나 넘치지 않으면 is-end 를 붙입니다.
Overlays
Tooltip
A bubble that shows a short description when an element is pointed at.요소를 가리킬 때 짧은 설명을 띄우는 말풍선입니다.
Mark it with role="tooltip" and associate it with the target via aria-describedby. Since it has no pointer-events, ensure the content is also reachable via keyboard focus.role="tooltip" 으로 표시하고 대상에 aria-describedby 로 연결합니다. pointer-events 가 없으므로 키보드 포커스로도 내용을 접근할 수 있게 합니다.
Overlays
Modal
A modal dialog presented over the screen.화면 위에 띄우는 모달 대화상자입니다.
.qf-modallayer: generic
Preview
Delete project
This action cannot be undone. The project and all its data will be permanently deleted.
<divclass="qf-modal"role="dialog"aria-modal="true"aria-labelledby="m-t"><divclass="qf-modal__header"><h2class="qf-modal__title"id="m-t">Delete project</h2><buttonclass="qf-btn qf-btn--icon qf-btn--lg qf-btn--ghost"aria-label="Close"><svgclass="qf-icon qf-icon--md"aria-hidden="true"><usehref="#qf-i-x"/></svg></button></div><divclass="qf-modal__body">This action cannot be undone. The project and all its data will be permanently deleted.</div><divclass="qf-modal__footer"><buttonclass="qf-btn qf-btn--ghost">Cancel</button><buttonclass="qf-btn qf-btn--danger">Delete</button></div></div>
Set role="dialog" and aria-modal="true", and associate the title via aria-labelledby. Trap focus within the modal, close on Esc, and move focus into it when it opens.role="dialog" 와 aria-modal="true" 를 지정하고 aria-labelledby 로 제목과 연결합니다. 포커스를 모달 안에 가두고 Esc 로 닫으며, 열릴 때 포커스를 옮깁니다.
Overlays
SettingsLayout
A settings layout split into a left navigation and a main content area.좌측 내비게이션과 본문 영역으로 나뉜 설정 레이아웃입니다.
Express the current selection on nav items with aria-selected and keep keyboard focus visible. Convey the selected state via aria attributes, not background color alone.내비 항목은 aria-selected로 현재 선택을 표현하고 키보드 포커스가 보이게 합니다. 선택 상태는 배경색뿐 아니라 aria 속성으로 함께 전달합니다.
Overlays
SettingsOverlay
A settings overlay presented over the full screen.전체 화면 위에 띄우는 설정 오버레이입니다.
.qf-settings-overlaylayer: generic
Preview
Settings
Edit app-wide settings such as account, notifications, and theme in a full-screen overlay. Lay it out with navigation on the left and a content area on the right.
<divclass="qf-settings-overlay__backdrop"></div><divclass="qf-settings-overlay__card"role="dialog"aria-modal="true"aria-label="Settings"><buttonclass="qf-settings-overlay__close"aria-label="Close">×</button><divclass="qf-stack"style="padding:var(--s-8)"><h2>Settings</h2><pstyle="color:var(--text-secondary);max-width:560px">Edit app-wide settings such as account, notifications, and theme in a full-screen overlay. Lay it out with navigation on the left and a content area on the right.</p></div></div>
Mark the card as a modal with role=dialog and aria-modal="true", trap focus, and close on Esc. Give the close button an aria-label.카드는 role=dialog와 aria-modal="true"로 모달임을 알리고 포커스를 가두며 Esc로 닫습니다. 닫기 버튼에는 aria-label을 둡니다.
Overlays
CommandPalette
A command and search palette opened via a keyboard shortcut.단축키로 여는 명령, 검색 팔레트입니다.
Indicate the current selection on result rows with aria-selected, and provide a cue beyond color via a left accent bar on the selected row. Ensure up and down keyboard navigation and visible focus, and convey empty results with text.결과 행은 aria-selected로 현재 선택을 알리고 선택 행은 좌측 accent bar로 색 외 단서를 함께 제공합니다. 키보드 위아래 이동과 포커스 가시를 보장하고, 빈 결과는 텍스트로 안내합니다.
Overlays
EmojiPicker
A picker for searching emoji and choosing them by category.이모지를 검색, 카테고리별로 골라 넣는 선택기입니다.
Convey state on category tabs and emoji cells with aria-selected, and add a cue beyond color via a bottom accent indicator on the selected tab. Surface the shortcode text in the bottom preview and ensure visible focus.카테고리 탭과 이모지 셀은 aria-selected로 상태를 전하고, 선택 탭은 하단 accent 표시로 색 외 단서를 더합니다. 하단 미리보기에 shortcode 텍스트를 함께 노출하고 포커스 가시를 보장합니다.
Overlays
UploadOverlay
A drag-and-drop guidance overlay shown while files are being dragged over a drop target.파일을 끌어다 놓는 동안 표시되는 드래그 앤 드롭 안내 오버레이입니다.
.qf-upload-overlaylayer: generic
Preview
Drop here to upload
Up to 50MB
<divclass="qf-upload-overlay"role="status"aria-live="polite"><divclass="qf-upload-overlay__icon"><svgclass="qf-icon"aria-hidden="true"><usehref="#qf-i-upload"/></svg></div><pclass="qf-upload-overlay__title">Drop here to upload</p><pclass="qf-upload-overlay__hint">Up to 50MB</p></div>
The overlay is purely visual with no pointer-events, conveying its action through a title and hint text. A dashed border is paired with guidance text so meaning is not carried by color alone.오버레이는 pointer-events 없이 시각 안내만 담당하며, 제목과 힌트 텍스트로 동작을 명확히 전달합니다. 점선 테두리와 함께 안내 문구를 두어 색 단독 의존을 피합니다.
Overlays
Popover
A floating panel of arbitrary content anchored to a trigger (free-form content, unlike a menu).트리거 기준으로 떠 있는 임의 콘텐츠 패널입니다(메뉴와 달리 자유 콘텐츠).
.qf-popoverlayer: generic
Preview
This is floating content.
<divclass="qf-popover"role="dialog"aria-label="Filter"><p>This is floating content.</p></div>
Set aria-haspopup/aria-expanded on the trigger and link it to the panel with aria-controls. Close on Esc and restore focus to the trigger, and move focus into the panel when it opens.트리거에 aria-haspopup/aria-expanded 를 두고 패널과 aria-controls 로 연결합니다. Esc 로 닫고 포커스를 트리거로 복원하며, 열릴 때 포커스를 패널로 옮깁니다.
Overlays
Drawer
A panel that slides in from the edge of the screen (right by default, with a left variant).화면 측면에서 슬라이드되는 패널입니다(우측 기본, 좌측 변형).
Announce it with role="dialog" and aria-modal="true", and trap focus inside the panel. Close on Esc and backdrop click, and restore focus to where it was before opening.role=dialog 와 aria-modal=true 로 알리고 포커스를 패널 안에 가둡니다. Esc 와 backdrop 클릭으로 닫고, 열기 전 포커스를 복원합니다.
Overlays
Lightbox
A chrome-free fullscreen contain-fit media viewer (zoom) or a full-bleed scrolling contact sheet. Unlike a dialog (qf-modal), it holds only media — no panel chrome.크롬 없는 풀스크린 contain-fit 미디어 뷰어(줌) 또는 풀블리드 스크롤 컨택트 시트입니다. 다이얼로그(qf-modal)와 달리 패널 크롬 없이 미디어만 담습니다.
role=dialog + aria-modal=true + aria-label. Trap focus, move focus to the close button on open, and restore it to the trigger on close. Close on Esc and scrim click (stop propagation on media clicks); the close button is 44px; respect prefers-reduced-motion.role=dialog + aria-modal=true + aria-label. 포커스를 가두고 열 때 닫기 버튼으로 포커스 이동, 닫을 때 트리거로 복원. Esc와 스크림 클릭으로 닫고(미디어 클릭은 stopPropagation), 닫기 버튼은 44px, prefers-reduced-motion을 존중합니다.
Disclosure
Accordion
A disclosure list whose sections expand and collapse when you click their header.제목을 눌러 내용을 펼치고 접는 디스클로저 목록입니다.
.qf-accordionlayer: generic
Preview
Shipping policy
Ships within 3 days.
<divclass="qf-accordion"><detailsclass="qf-accordion__item"open><summaryclass="qf-accordion__trigger">Shipping policy</summary><divclass="qf-accordion__panel">Ships within 3 days.</div></details></div>
Built on native details/summary, so keyboard toggling and expanded-state communication come for free. Put meaningful header text in the summary (qf-accordion__trigger).네이티브 details/summary 기반이라 키보드 토글과 펼침 상태 전달이 기본 제공됩니다. summary(qf-accordion__trigger)에 의미 있는 제목 텍스트를 둡니다.
Pattern
Full chat mockup
A real screen assembled entirely from the components above. The same 3-column layout as Discord.위 컴포넌트로만 조립한 실제 화면. Discord와 동일한 3-column 레이아웃.
qufox team
▾ PRODUCT
announcements 2
general
design
voice-lounge
▾ ENGINEERING
frontend
backend 12
general
Announcements, General chat공지, 일반 대화
dev_leeMOD2:34 PM오후 2:34
All the brand assets are in. @designer_kim please take a look!브랜드 에셋 다 반영했습니다. @designer_kim 확인 부탁!
🦊5
🚀2
designer_kim2:38 PM오후 2:38
Looks good! Just double-check that the --r-xl value is applied to the cards.좋아요! --r-xl 값 카드에 적용했는지만 확인해주세요.
And the favicon looks great too 👀그리고 파비콘도 잘 보이네요 👀
pm_choi is typing…pm_choi 입력 중…
ONLINE — 3
founder_park
dev_lee
designer_kim
OFFLINE — 8
eng_jung
ops_han
Assets
Icon pack: 100+
All the icons your chat UI needs in one set. Every icon is drawn as 24×24 viewBox, SVG path, stroke=currentColor and covers Discord/Slack patterns. Set the color via CSS color and the size via the size modifier.채팅 UI에 필요한 아이콘을 한 세트로. 모두 24×24 viewBox, SVG path, stroke=currentColor로 그려졌고, Discord/Slack 패턴을 덮습니다. 색상은 CSS color로, 크기는 사이즈 modifier로 조절해요.
Usage
<!-- 1. Load once in the document -->
<link rel="stylesheet" href="icons.css">
<!-- 2. Reference by symbol ID -->
<svg class="qf-icon"><use href="icons.svg#qf-i-send"/></svg>
<!-- Size / color modifiers -->
<svg class="qf-icon qf-icon--sm">...</svg> /* 16 */
<svg class="qf-icon qf-icon--lg qf-icon--accent">...</svg>
Sizes
sm: 16
md: 20
lg: 24
xl: 28
Colors
currentColor
--accent
--muted
success
danger
In-context examples
in buttons
message hover toolbar
Message #general
composer
voice controls
Online
Idle
Do not disturb
presence
Edit message
Pin message
Copy link
Delete
dropdown menu
Full list전체 목록
Click to copy the <use href="#..."/> string.클릭하면 <use href="#..."/> 문자열이 복사돼요.
copied
Pattern
Auth — Login & sign-up
Drop-in authentication screens built only from generic components — qf-card, qf-field, qf-input, qf-btn, qf-notice, qf-strength-meter. Accent and surfaces follow the active brand — switch Brand or theme in the top bar to watch them re-skin — and the symbol comes from brand.config.json, so every white-label customer gets these screens for free.범용 컴포넌트(qf-card, qf-field, qf-input, qf-btn, qf-notice, qf-strength-meter)만으로 구성한 즉시 사용 가능한 인증 화면입니다. accent와 표면은 활성 브랜드를 따라 — 상단에서 Brand나 테마를 바꾸면 다시 칠해집니다 — 심볼은 brand.config.json에서 와서, 모든 화이트라벨 고객이 이 화면을 그대로 쓸 수 있습니다.
Form feedback uses the same notice and field-error patterns, so the affordance never relies on color alone — each message carries an icon and text, and live regions announce errors to screen readers.폼 피드백은 동일한 notice와 field-error 패턴을 써서 색에만 의존하지 않습니다 — 각 메시지는 아이콘과 텍스트를 함께 두고, 라이브 영역이 오류를 스크린리더에 통지합니다.
Your session expired, so you were signed out. Please log in again.세션이 만료되어 로그아웃되었습니다. 다시 로그인해 주세요.
This account is deactivated. You can restore it within 30 days.비활성화된 계정입니다. 30일 이내라면 복구할 수 있습니다.
App screens
Workspace, Discover
New workspace creation flow and browsing public workspaces. Category metadata (emoji, labels) follows WORKSPACE_CATEGORY_META.새 워크스페이스 생성 플로우와 공개 워크스페이스 둘러보기. 카테고리 메타(이모지, 라벨)는 WORKSPACE_CATEGORY_META를 따릅니다.
Discover: Desktop
Top search + category segment + card grid. The join button is .qf-btn--primary.상단 검색 + 카테고리 segment + 카드 그리드. 참여 버튼은 .qf-btn--primary.
Public workspaces공개 워크스페이스
Q
qufox Design Guildqufox 디자인 길드
🎨 Art, 248 members🎨 예술, 248명
A space where designers gather to share their process and exchange feedback.디자이너들이 모여 작업 과정을 공유하고 피드백을 주고받는 공간.
F
Frontend KoreaFrontend 한국
💻 Dev, 1,204 members💻 개발, 1,204명
A community studying modern frontend together — React, Vue, Svelte, and more.React, Vue, Svelte 등 모던 프론트엔드를 함께 공부하는 커뮤니티.
G
Game Dev Lounge
🎮 Gaming, 87 members🎮 게임, 87명
A small gathering where indie game developers share their work and trade feedback.인디 게임 개발자들이 작업물 공유하고 피드백하는 작은 모임.
Create workspace: Desktop modal
Create a new workspace새 워크스페이스 만들기
Create a space to chat with your friends and team. You can change this later.내 친구들, 팀과 대화할 공간을 만들어보세요. 나중에 변경할 수 있어요.
qufox.app/w/
Lowercase letters, numbers, and hyphens only소문자, 숫자, 하이픈만 가능
Public workspace공개 워크스페이스
Listed in Discover so anyone can request to joinDiscover에 노출되어 누구나 참여 요청 가능
Mobile
Discover찾기
Public workspaces공개 워크스페이스
New workspace새 워크스페이스
/w/
Public공개
Listed in DiscoverDiscover에 노출
App screens
Channel settings
Split into Overview, Members, and Permissions tabs. A Discord-style left nav pattern, but on mobile it collapses into a single scroll plus a segment control.개요, 멤버, 권한 탭으로 분리. Discord와 같은 좌측 nav 패턴이지만 모바일에서는 단일 스크롤 + segment로 압축.
Desktop: Overview tab
Overview개요
Configure the channel's basic information.채널의 기본 정보를 설정합니다.
Shown in the channel header.채널 헤더에 표시됩니다.
Private channel비공개 채널
Only invited members can view it.초대된 멤버만 볼 수 있어요.
Slow mode슬로우 모드
Minimum 5-second interval between messages메시지 사이 최소 5초 간격
Desktop: Members tab
Members멤버42
Member멤버
Role역할
Joined가입
Y유
Yujin유진
@yujin
Owner소유자
2024.01.12
M민
Minseo민서
@minseo
Admin관리자
2024.02.03
J지
Jiho지호
@jiho
Member멤버
2024.03.18
S소
Soyoung소영
@soyoung
Member멤버
2024.04.02
Mobile
#general
Channel settings채널 설정
Private비공개
Invited members only초대된 멤버만
Slow mode슬로우 모드
5-second interval5초 간격
Members: 42멤버: 42
#general
Admins: 3관리자: 3
Members: 39멤버: 39
App screens
Channel, Category modals
New channel, new category, creating a channel inside a category. All use the same modal component + .qf-toggle-row pattern.새 채널, 새 카테고리, 카테고리 안에 채널 만들기. 모두 같은 modal 컴포넌트 + .qf-toggle-row 패턴.
Desktop: Create Channel
Create Channel채널 만들기
Add a new channel to the PRODUCT category.PRODUCT 카테고리에 새 채널을 추가합니다.
Private channel비공개 채널
Only selected members and roles can see it.선택한 멤버와 역할만 볼 수 있어요.
Desktop: Create Category
Create Category카테고리 만들기
Group related channels together to keep things organized.관련된 채널들을 묶어서 정리할 수 있어요.
Private category비공개 카테고리
All sub-channels are synced to private.하위 채널이 모두 비공개로 동기화됩니다.
Mobile: Bottom sheet
Create Channel채널 만들기
Private비공개
ENGINEERING categoryENGINEERING 카테고리
App screens
Threads
Split follow-up conversations off a message inline. Desktop uses a right-hand side panel, mobile uses a full-screen route.메시지의 후속 대화를 인라인으로 분리. 데스크톱은 우측 사이드 패널, 모바일은 풀스크린 라우트.
Desktop: Thread panel beside chat
qufox team
▾ PRODUCT
general
design
announcements 2
general
Team-wide announcements팀 전체 공지
E유
Eugene유진Today 10:42 AM오늘 오전 10:42
It would be good to write up the major changes going into the next release. Please review the PR below 🙏다음 릴리즈에 들어갈 큰 변경사항 정리해두면 좋을 것 같아요. 아래 PR 리뷰 부탁드립니다 🙏
M민
Minseo민서10:48 AM오전 10:48
This behaves the same on mobile too, right? I added test cases.이거 모바일에서도 같은 동작 맞죠? 테스트 케이스 추가했어요.
7 replies7개의 답글, Latest: 12 minutes ago, 가장 최근: 12분 전
J지
Jiho지호11:02 AM오전 11:02
I think we should merge the design token PR along with it.디자인 토큰 PR도 같이 머지하면 좋을 것 같아요.
Mobile: Full-screen thread
Thread스레드
#general, 7 replies7개의 답글
Minseo민서10:48 AM오전 10:48
This behaves the same on mobile too, right? I added test cases.이거 모바일에서도 같은 동작 맞죠? 테스트 케이스 추가했어요.
7 replies7개의 답글
E유
Eugene유진11:05
Right. Please double-check once more on iOS Safari.맞아요. iOS Safari에서 한 번 더 확인 부탁드려요.
Please look at the scroll performance too 🙏스크롤 성능도 같이 봐주세요 🙏
M민
Minseo민서11:14
Tests passed ✅테스트 통과했습니다 ✅
J지
Jiho지호11:22
I think you can go ahead and merge!머지하셔도 될 것 같아요!
App screens
DM shell
One-on-one conversations with friends, no workspace required. DM list on the left plus the main conversation area. On mobile, the list and conversation are separate routes.워크스페이스 없이도 친구와 1:1 대화. 좌측 DM 리스트 + 메인 대화 영역. 모바일은 리스트와 대화가 별도 라우트.
Gunwoo: How about tomorrow afternoon?건우: 내일 오후 어때요?
G건
Gunwoo건우
See you tomorrow!내일 봬요!
M민
Minseo민서
@minseo, Online@minseo, 온라인
Wednesday, May 22, 20242024년 5월 22일 수요일
M민
Minseo민서10:14 AM오전 10:14
Finished the PR review. I left a few comments.PR 리뷰 끝났어요. 코멘트 몇 개 남겨놨습니다.
Y유
Yujin유진10:32 AM오전 10:32
Thank you! I'll make the changes and let you know.감사합니다! 반영하고 다시 알려드릴게요.
M민
Minseo민서11:14 AM오전 11:14
All tests passed ✅테스트 통과했습니다 ✅
I think it's good to merge머지해도 될 것 같아요
Mobile
Messages메시지
M민
Minseo민서
Direct message, Online다이렉트 메시지, 온라인
Wednesday, May 225월 22일 수요일
M민
Minseo민서10:14
Finished the PR review. I left a few comments.PR 리뷰 끝났어요. 코멘트 몇 개 남겨놨습니다.
Y유
Yujin유진10:32
Thank you! I'll make the changes and let you know.감사합니다! 반영하고 다시 알려드릴게요.
M민
Minseo민서11:14
All tests passed ✅테스트 통과했습니다 ✅
I think it's good to merge머지해도 될 것 같아요
App screens
Friends
Friends list + incoming/outgoing requests + user blocking. The 4-tab segment pattern is identical on desktop and mobile.친구 목록 + 받은/보낸 요청 + 사용자 차단. 4-탭 segment 패턴은 데스크톱, 모바일 동일.
Desktop: All friends
Friends친구
All friends — 8전체 친구 — 8
M민
Minseo민서
@minseo, Online@minseo, 온라인
J지
Jiho지호
@jiho, Away@jiho, 자리 비움
S소
Soyoung소영
@soyoung, Offline@soyoung, 오프라인
G건
Gunwoo건우
@gunwoo, Do not disturb@gunwoo, 방해 금지
Desktop: Pending requests
Friend requests친구 요청
Incoming requests — 2받은 요청 — 2
H하
Haneul하늘
@haneul, Incoming request@haneul, 받은 요청
B바
Bada바다
@bada, Incoming request@bada, 받은 요청
Outgoing requests — 1보낸 요청 — 1
G강
Gangsan강산
@gangsan, Awaiting response@gangsan, 응답 대기 중
Mobile
Friends친구
All friends, 8전체 친구, 8
Pending대기 중
Incoming requests, 2받은 요청, 2
H하
Haneul하늘
@haneul
B바
Bada바다
@bada
Outgoing requests, 1보낸 요청, 1
Mobile
Mobile system
Mobile layout based on Discord/Slack patterns. Touch targets 44×44 or larger, automatic safe-area inset handling, optimized for one-handed operation with a bottom tab + bottom sheet combination.Discord/Slack 패턴 기반의 모바일 레이아웃. 터치 타겟 44×44 이상, safe-area inset 자동 처리, bottom tab + bottom sheet 조합으로 한 손 조작 최적화.
Layout patterns
The mobile primitives (qf-m-*) are documented individually — see the qufox app (chat module) group in the sidebar (topbar, tab bar, bottom sheet, list rows, composer) and the full chat mockup for assembled iOS/Android screens (same classes on both).qf-m-* 모바일 프리미티브는 개별 페이지로 문서화돼 있습니다 — 사이드바 qufox app (chat module) 그룹(topbar, tab bar, bottom sheet, list row, composer)과 조립된 iOS/Android 화면은 full chat mockup을 참고하세요(양 플랫폼 동일 클래스).
Mobile-only tokens
--m-topbar-h: 52px; /* top nav height */
--m-tabbar-h: 56px; /* bottom tab bar (excludes safe-area) */
--m-composer-h: 56px; /* message input field */
--m-touch: 44px; /* minimum hit target (Apple HIG) */
--m-gutter: 16px; /* left/right padding */
--m-sheet-r: 20px; /* bottom sheet top radius */
Core components핵심 컴포넌트
.qf-m-screen
Top-level shell. topbar + scrollable body + tabbar/composer structure.최상위 쉘. topbar + scrollable body + tabbar/composer 구조.
Bottom nav with 4 tabs (Home, DMs, Activity, You). Automatic safe-area.바닥 네비 4탭 (Home, DMs, Activity, You). safe-area 자동.
.qf-m-composer
Chat input field. 3 elements: + / text / send. Rounded pill.채팅 입력창. + / 텍스트 / 전송 3요소. 라운드 pill.
.qf-m-sheet
Bottom sheet (action menu, emoji reactions). grab bar + items.Bottom sheet (액션 메뉴, 이모지 반응). grab bar + items.
.qf-m-fab
Floating action button. Primary actions such as new DM, new post.플로팅 액션 버튼. 새 DM, 새 글 등 primary action.
.qf-m-row
List row (DM, member, server). 64px minimum height, left avatar + 2-line text + aside.리스트 행 (DM, 멤버, 서버). 64px 최소 높이, 좌측 avatar + 2단 텍스트 + aside.
.qf-m-segment
Segmented control (filter switching like All/Mentions/Threads).Segmented control (All/Mentions/Threads 같은 필터 전환).
.qf-m-voice
Voice room grid + controls. speaking state outline.보이스 룸 그리드 + 컨트롤. speaking 상태 outline.
Rules규칙
Touch targets: Every interactive element is at least 44×44. When it needs to look smaller, secure the hit area with padding.터치 타겟: 모든 인터랙티브 요소는 최소 44×44. 작아 보여야 하는 경우 padding으로 hit area 확보.
Safe area: topbar uses env(safe-area-inset-top), tabbar/composer reflect the bottom inset. Already built into the components.Safe area: topbar는 env(safe-area-inset-top), tabbar/composer는 bottom inset 반영. 이미 컴포넌트에 내장.
Drawer pattern: Server/channel lists use a hamburger menu → left drawer. The member list is a right drawer (Discord style).Drawer 패턴: 서버/채널 리스트는 햄버거 메뉴 → 좌측 drawer. 멤버 리스트는 우측 drawer (Discord 방식).
Bottom sheet: Desktop context menus/modals convert to bottom sheets on mobile. Make it scrollable when there are 5 or more options.Bottom sheet: 데스크톱의 context menu/modal은 모바일에서 bottom sheet로 변환. 옵션 5개 이상이면 스크롤 가능하게.
Long-press = context menu: Long-press a message → bottom sheet + reaction emoji row.Long-press = context menu: 메시지 long-press → bottom sheet + 반응 이모지 row.
Swipe to reply: Swipe a message right → reply mode (native pattern).Swipe to reply: 메시지 우측 스와이프 → 답글 모드 (네이티브 패턴).
Keyboard dodge: The composer rises together with the keyboard. The body shrinks automatically.키보드 dodge: composer는 키보드 올라올 때 함께 올라감. body는 자동 축소.
A Slack-grade rich composer with drop-up autocomplete. The format bar expands with qf-composer--rich or on focus-within, and @mentions, #channels, :emoji, and slash commands all share one skeleton.Slack 수준의 rich 컴포저와 드롭업 자동완성이에요. 포맷바는 qf-composer--rich 또는 focus-within 시 펼쳐지고, @멘션, #채널, :이모지, 슬래시 커맨드가 한 골격을 공유합니다.
Composer
A rich state with the format bar forced open, and an empty default state (send disabled).포맷바를 강제로 펼친 rich 상태와, 비어 있는 기본 상태(전송 비활성).
Enter Send, Shift+Enter New lineEnter 전송, Shift+Enter 줄바꿈42 / 2000
.qf-composer, .qf-composer--rich
Autocomplete
A drop-up that appears above the composer. The demo lays out only the inner card inline, without a backdrop (position:static).컴포저 위로 뜨는 드롭업. 데모는 backdrop 없이 inner 카드만 인라인 배치(position:static).
Members
Design_Kim디자인_김@designer_kim
Dev_Lee개발_이@dev_lee
@mention: --mention@멘션: --mention
Channels
#
general일반120 members멤버 120명
#
design-system디자인-시스템24 members멤버 24명
#
deploy-alerts배포-알림8 members멤버 8명
#channel: --channel#채널: --channel
Emoji
🎉:tada:
🚀:rocket:
🦊:fox:
:emoji: --emoji:이모지: --emoji
Slash menu
A slash-command-only variant — leading slash icon + monospace command name + description hierarchy.슬래시 커맨드 전용 변형 — 좌측 슬래시 아이콘 + monospace 커맨드명 + 설명 위계.
Commands
/
/giphy[search term][검색어]
Sends a searched GIF to the channel검색한 GIF를 채널에 보냅니다
↵
/
/remind[who] [what] [when][누가] [무엇] [언제]
Sends a reminder at the specified time지정한 시각에 리마인더를 보냅니다
/
/shrug
Appends ¯\_(ツ)_/¯ to the end of your message¯\_(ツ)_/¯ 를 메시지 끝에 덧붙입니다
.qf-slash-menu
v4: Task 050
Command Palette, Emoji
A ⌘K quick switcher and emoji picker. In this demo we show only the inner card inline, without a fixed backdrop — in the actual app it floats above .qf-cmd-palette-backdrop.⌘K 빠른 전환기와 이모지 피커예요. 데모에서는 fixed backdrop 없이 inner 카드만 인라인으로 보여줍니다 — 실제 앱에서는 .qf-cmd-palette-backdrop 위에 떠 있어요.
Command palette
A large search input on top + section headers + result rows (icon, label, path/kbd). The selected row is highlighted with a left accent bar.상단 큰 검색 입력 + 섹션 헤더 + 결과 row(아이콘, 라벨, 경로/kbd). 선택 행은 좌측 accent bar로 강조.
Channels채널
general일반qufox HQ
general-design일반-디자인qufox HQ
Direct messages다이렉트 메시지
designer_kimOnline온라인
Commands커맨드
Toggle theme테마 전환⌘⇧T
Open preferences환경설정 열기⌘,
.qf-cmd-palette: section / row / kbd
Emoji picker
Search + category tabs + 9-column grid + preview at the bottom. Fixed 350×420 card.검색 + 카테고리 탭 + 9열 그리드 + 하단 preview. 350×420 고정 카드.
Smileys, People스마일, 사람
😀:grinning:
.qf-emoji-picker: tabs / grid / preview
v4: Task 050
Overlays, Banners
Status picker, hovercard, 4 banner types, shortcut sheet, role chips, search/upload overlays, and embed variants. The floating surfaces are rendered inline as cards only, without a backdrop.상태 피커, hovercard, 배너 4종, 단축키 시트, 역할 칩, 검색/업로드 오버레이, 임베드 변형이에요. 플로팅 면은 backdrop 없이 카드만 인라인으로 렌더했습니다.
Status picker, Hovercard
Status selection popover and user profile hovercard.상태 선택 팝오버와 유저 프로필 hovercard.
Online온라인
Away자리 비움
Do Not Disturb방해 금지You will not receive notifications알림을 받지 않습니다
Offline오프라인
Yuna Park박유나
@yuna
Online, Designing온라인, 디자인 중
AdminDesign
The person building the qufox design system. Loves the color purple.qufox 디자인 시스템을 만드는 사람. 보라색을 좋아합니다.
.qf-status-picker, .qf-hovercard
Banner
info, warn, danger, accent — 4 variants. 4px left status-color bar + tint.info, warn, danger, accent 4변형. 좌측 4px 상태색 바 + 틴트.
A new version has been deployed. Refresh to apply it.새 버전이 배포되었습니다. 새로고침하면 적용됩니다.
Your connection is unstable. Message delivery may be delayed.연결이 불안정합니다. 메시지 전송이 지연될 수 있습니다.
Subscription expired — some features are now restricted.구독 만료 — 일부 기능이 제한되었습니다.
Try out the voice channel beta.음성 채널 베타에 참여해 보세요.
Keyboard shortcut sheet, Role chips
Shortcut sheet (two-column groups) and role chip variants.단축키 시트(2열 그룹)와 역할 칩 변형.
Navigation탐색
Quick switcher빠른 이동⌘+K
Search검색⌘+F
Mark as read읽음 처리Esc
Messages메시지
Edit last마지막 편집↑
Reply답장R
Emoji이모지⌘+E
AdminModeratorActiveBot
.qf-kbd-sheet, .qf-role-chip
Search overlay
Search bar + from:/in:/has: filter chips + result preview.검색바 + from:/in:/has: 필터 칩 + 결과 미리보기.
from:designer_kimin:general일반has:link
designer_kim, # general, 2:34 PMdesigner_kim, # 일반, 오후 2:34
Finalized the logo size at 120×40. I'll send over the SVG.로고 크기 120×40으로 확정했어요. SVG 넘겨드릴게요.
Finished deploying the new logo assets.새 로고 에셋 배포 완료했습니다.
Jump
.qf-search-overlay
Upload overlay
A dashed drag-and-drop overlay above the chat area (it is position:absolute, so it nests inside a position:relative box).채팅 영역 위 드래그앤드롭 점선 오버레이(position:absolute이므로 position:relative 박스 안에 안착).
Upload to # general# 일반에 업로드
Drag and drop your files here: 25MB max파일을 여기에 끌어다 놓으세요: 최대 25MB
.qf-upload-overlay
Embed variants
Image, video, bot/app message embeds.이미지, 비디오, 봇/앱 메시지 임베드.
.qf-embed--image
.qf-embed--video
qufox-bot APP
Deployment complete배포가 완료되었어요
main → NAS auto-deploy succeeded. /readyz 200 OK.main → NAS 자동 배포 성공. /readyz 200 OK.
.qf-embed--bot
v4: Task 050
Message actions, Density
Quick reactions on message hover, a reaction-add pill, code-block headers with copy, thread-follow avatar stacks, and a side-by-side comparison of the same message at cozy and compact densities.메시지 hover 빠른 반응, 반응 추가 pill, 코드블록 헤더/복사, 스레드 참여 아바타 스택, 그리고 같은 메시지를 cozy와 compact 밀도로 나란히 비교합니다.
Quick-react, Reaction add
Three quick-reaction slots plus a more button inside the hover action bar, with a dashed add pill at the end of the reaction row.hover 액션바 내부 빠른 반응 3슬롯 + 더보기, 그리고 반응 행 끝의 dashed 추가 pill.
dev_leeMODToday 2:34 PM오늘 오후 2:34
Shipping the density toggle today. I'll wire up reactions right away too.밀도 토글 오늘 배포합니다. 반응도 바로 붙여볼게요.
.qf-msg-quickreact, .qf-reaction--add
Code block header, Thread follow-up
A header atop the code block (language + copy) and a thread-follow avatar stack with an accent count.코드블록 상단 헤더(lang + 복사)와 스레드 참여 아바타 스택 + accent 카운트.
typescript
const density = useDensity(); // 'cozy' | 'compact'
The same message group rendered side by side in the default container and a data-density="compact" container for comparison.같은 메시지 그룹을 기본 컨테이너와 data-density="compact" 컨테이너로 나란히 렌더해 비교.
Cozy (default)(기본)
designer_kim10:24 AM오전 10:24
Cozy keeps the 40px avatar and generous spacing.cozy는 40px 아바타와 넉넉한 간격을 유지해요.
Consecutive messages align to the same width.연속 메시지도 같은 폭으로 정렬됩니다.
The reading flow carries smoothly through.읽기 흐름이 부드럽게 이어져요.
Default container기본 컨테이너
Compact
designer_kim10:24 AM오전 10:24
Compact shrinks the avatar and tightens the gap between groups.compact는 아바타를 줄이고 그룹 간격을 좁혀요.
Consecutive messages are indented by the avatar width.연속 메시지는 아바타 폭만큼 인덴트됩니다.
Vertical density goes up while alignment stays the same.세로 밀도는 높이고 정렬은 그대로.
data-density="compact"
v4: Task 050
Mobile nav, IA
This is the mobile information-architecture upgrade. It shows, one screen at a time, the bottom tab bar with active pill, the OverlappingPanels left drawer, message-screen ergonomics, Home quick tiles/filters/profile, and the emoji drawer.모바일 정보구조 업그레이드예요. 하단 탭바 활성 pill, OverlappingPanels 좌 드로어, 메시지 화면 ergonomics, Home 퀵타일/필터/프로필, 그리고 이모지 드로어를 한 컷씩 보여줍니다.
Tab bar, Panels, Message ergonomics
(a) Tab bar with active pill + badges, (b) OverlappingPanels with the left drawer open, (c) unread divider + jump button + accessory bar.(a) 활성 pill + 배지 탭바, (b) 좌 드로어 열린 OverlappingPanels, (c) 읽지 않음 divider + jump 버튼 + accessory 바.
Home홈
Recent conversations최근 대화
designer_kim
Sent over the SVG, please take a look!SVG 넘겨드렸어요 확인 부탁!
2:34
# deploy-alerts# 배포-알림
Deployment completed배포가 완료되었어요
Yesterday어제
Text channels텍스트 채널
# general# 일반
# design# 디자인
# deploy# 배포
# design# 디자인
designer_kim2:14 PM오후 2:14
Putting the panel skeleton in place.패널 골격 들어갑니다.
# general# 일반
New messages새 메시지7
designer_kim9:41 AM오전 9:41
Uploading a few photos사진 몇 장 올려요
+5
Home IA, You, Emoji drawer
(d) Home quick tiles + filter chips + You header, plus a single shot of the mobile emoji drawer.(d) Home 퀵타일 + 필터칩 + You 헤더, 그리고 모바일 이모지 드로어 한 컷.