Files
HMDesign/docs/components/label.md

7.3 KiB

Label

현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Label 고유의 API·Token·상태·결정만 기록한다.

1. 상태

항목 내용
구현 상태 HM 스타일 적용 완료 (typography·color만, hm-label class 없음)
기준일 2026-10-02
기반 shadcn/ui Label (Radix Label)
대표 Story Components/Form/Label → All (이름 "Label")
보류 아래 §11

2. 적용 근거

  • ui_viz에는 독립 Label 문서가 없다. Field Label 역할은 Input·Textarea가 소유한다: docs/components/input.md §9(14/20/500, label-md), §10·§16(color.fg.secondary #6E6759, Confirmed), textarea.md §2.2·§2.
  • ui_viz Confirmed (Input·Textarea Field Label 범위): 14 / 20 / 500, 색 color.fg.secondary. (Source 13/700은 CANONICAL_OVERRIDE로 14/20/500이 확정. D-093 원본 실행본 13/700은 KNOWN_DEVIATION / FOLLOW_UP.)
  • shadcn/Radix 유지: 라벨 연결(htmlFor/감싸기), 클릭 시 컨트롤 focus, select-none, Disabled 연동 class.
  • Required 표시, Checkbox/Radio option label의 별도 규칙은 ui_viz에 없다 → §11.

3. 기본 규격

항목 값
Typography 14 / 20 / 500
색 --hm-sem-fg-secondary (#6E6759)
배치 flex w-fit items-center gap-2 (shadcn 기본, 부모 grid에서 시작 정렬)

Label ↔ Control 간격 8px(input.field.gap)은 Field 조합의 값이며 Label이 소유하지 않는다.

4. 상태 규격

상태 값
Default 위 기본 규격
Disabled shadcn 기본: 연결된 컨트롤이 peer이고 disabled면 opacity-50, cursor-not-allowed (또는 상위 group[data-disabled=true])

Hover/Focus/Active 스타일 없음.

5. API

Radix Label props 그대로 (htmlFor, asChild 등). 출력 속성: data-slot="label".

  • Required 표시(*)를 위한 prop은 만들지 않았다(ui_viz field-semantics.md §1: Select/Checkbox/Radio 등에 required API·표시를 새로 추가하지 않는다). 소비자가 aria-hidden span으로 조합한다.

신규 업무 화면의 연결 예제

Label은 @hm-design/ui에 공개 export되어 있다. 지원하는 Field Label은 직접 스타일링한 native <label> 대신 실제 Label을 렌더한다. Input/Textarea는 id, Select는 Root가 아닌 SelectTrigger의 id, Combobox는 trigger로 전달되는 공개 id에 연결한다. aria-labelledby로 화면에 보이는 항목명을 접근성 이름으로 함께 사용한다.

import { useId } from "react"
import { Label, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Combobox } from "@hm-design/ui"

export function Fields() {
  const id = useId()
  return <>
    <Label htmlFor={`${id}-name`}>이름</Label>
    <Input id={`${id}-name`} size="medium" />
    <Label id={`${id}-type-label`} htmlFor={`${id}-type`}>유형</Label>
    <Select>
      <SelectTrigger id={`${id}-type`} aria-labelledby={`${id}-type-label`} size="medium"><SelectValue placeholder="선택" /></SelectTrigger>
      <SelectContent><SelectItem value="work">업무</SelectItem></SelectContent>
    </Select>
    <Label id={`${id}-owner-label`} htmlFor={`${id}-owner`}>담당자</Label>
    <Combobox id={`${id}-owner`} aria-labelledby={`${id}-owner-label`} options={[{ value: "kim", label: "김한맥" }]} size="medium" />
  </>
}

Label/control 간격은 부모 조합이 소유한다. 반복 Field는 인스턴스별 ID를 사용하며, Label 클릭 focus와 팝업 키보드·접근성 이름은 실제 브라우저에서 확인한다. 위 예제는 기존 공개 props를 사용하며 새 label/required prop을 만들지 않는다. native Label 사용을 무조건 금지하지 않는다. 명시적인 비 React adapter 또는 기존 HM Label로 연결할 수 없는 사용처는 지원 제약·의미 있는 HTML 선택 이유·접근성 확인 결과를 기록한다. Story에 남은 native Label fixture만으로 신규 화면의 예외를 인정하지 않는다.

6. Token

Component Mapping 위치: packages/ui/src/theme/label.css (--hm-label-*).

  • --hm-label-font-size(14px), --hm-label-line-height(20px), --hm-label-font-weight(500), --hm-label-text(→ --hm-sem-fg-secondary).
  • Primitive 신규 추가 없음.

7. shadcn / Radix에서 유지한 항목

Radix Label 동작·접근성, data-slot, cn(..., className), select-none, group-data-[disabled=true]·peer-disabled 연동.

8. HM에서 변경한 항목

  • shadcn leading-none font-medium text-sm 대신 theme CSS가 typography·색을 정한다.
  • flex 라벨이 한 줄 전체를 차지하지 않도록 w-fit을 추가(ui_viz Label justify-self: start).

9. Storybook

  • 대표 Story All("Label"): 구역 default(htmlFor), required(소비 조합), disabled, long.
  • 별도 verification Story 없음(구역이 단순).

10. 사용자 확정 결정

  • 2026-10-11 최종 사용자 결정: Input Story 소비 조합의 Disabled Label은 원본 색 #6E6759 / opacity 0.6을 적용한다. 공통 Label Component의 Disabled 0.5는 그대로 유지한다. Input 기본·readOnly·Error Label은 Disabled가 아니면 1, Message / Helper Text는 기존 구현 유지다. 이 결정은 공통 Label API·Theme·Checkbox/Switch/Radio Label 규칙으로 확대하지 않는다.

11. 미확정 / 보류

  • 독립 Label 규격 없음. Input·Textarea Field Label 값을 Label 컴포넌트에 적용한 것이다. Checkbox/Radio option label의 전경 role은 ui_viz TBD(field-semantics.md §3)이므로 해당 컴포넌트 작업에서 따로 확인한다.
  • Disabled opacity의 과거 기록: Input의 "Label·Message 포함 .6"(2026-10-02 Input 한정 결정)은 공통 Label로 확대하지 않고 shadcn 기본 0.5를 유지했다. 2026-10-11 최종 결정은 Input Story 소비 Label만 0.6으로 적용하며, Message는 변경하지 않는다. 이전 검토의 “Label 100% 유지”와 과거 검증은 당시 기록이고 현재 정책은 §10을 따른다.
  • Required 표시 색(#D32F2F, TEXTAREA-07)과 표시 방식은 소비 조합이다. 컴포넌트 API 없음.
  • D-093 원본 실행본 13/700: KNOWN_DEVIATION / FOLLOW_UP.

12. 관련 파일

packages/ui/src/components/ui/label.tsx
packages/ui/src/theme/label.css
packages/ui/src/theme.css            (import)
packages/ui/src/index.ts             (export Label)
src/components/label.stories.tsx

13. 검증 상태

  • npm run typecheck, npm run build: 통과(2026-10-02).
  • Storybook computed style(components-form-label--all): 14px / 20px / 500, color rgb(110,103,89), Disabled 연결 시 opacity 0.5.
  • 라벨 클릭 시 연결된 input으로 실제 focus 이동 확인.
  • 2026-10-02 당시 미확인: 사이드바 화면, 390px 폭, Checkbox/Radio와의 조합. 현재 Checkbox/Radio는 구현되어 있으나 이 과거 검증 기록이 조합 검증 완료를 뜻하지는 않는다.
  • 2026-10-11 선택 회귀: 실제 공통 Label 대표 Story Disabled의 색 rgb(110, 103, 89) / opacity 0.5, 부모 1, disabled Input과의 htmlFor 연결 확인. 공통 Label 구현·Theme는 변경하지 않았다. Input Story Label 60% 별도 결정 및 검증.