FormLabel#
폼 입력에 붙는 설명 라벨입니다. isRequired 가 true 면 라벨 뒤에 필수 표시(*)를 붙입니다(커스텀 표시는
requiredIndicator, 기본은 error 색 별표). Flutter / Web 1:1 동일 API 입니다.
Live Preview#
class FormLabelDefaultExample extends StatelessComponent {
const FormLabelDefaultExample({super.key});
@override
Component build(BuildContext context) {
return FormLabel(label: Text('이메일'), isRequired: true);
}
}
class FormLabelDefaultExample extends StatelessWidget {
const FormLabelDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return FormLabel(label: const Text('이메일'), isRequired: true);
}
}
class FormLabelChainExample extends StatelessComponent {
const FormLabelChainExample({super.key});
@override
Component build(BuildContext context) {
return FormLabel(
label: Text('이메일'),
isRequired: true,
).withStyle(
const CoreFormLabelStyle(
labelStyle: CoreTextStyle.token(
CoreTextStyles.titleMedium,
color: CoreColor.token(CoreColors.primary),
),
requiredColor: CoreColor.token(CoreColors.tertiary),
requiredIndicatorGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
class FormLabelChainExample extends StatelessWidget {
const FormLabelChainExample({super.key});
@override
Widget build(BuildContext context) {
return FormLabel(
label: const Text('이메일'),
isRequired: true,
).withStyle(
const CoreFormLabelStyle(
labelStyle: CoreTextStyle.token(
CoreTextStyles.titleMedium,
color: CoreColor.token(CoreColors.primary),
),
requiredColor: CoreColor.token(CoreColors.tertiary),
requiredIndicatorGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
사용법#
FormLabel(label: const Text('이메일'), isRequired: true)
빠른 오버라이드 (Chain)#
이미 만든 FormLabel 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.
class FormLabelChainExample extends StatelessWidget {
const FormLabelChainExample({super.key});
@override
Widget build(BuildContext context) {
return FormLabel(
label: const Text('이메일'),
isRequired: true,
).withStyle(
const CoreFormLabelStyle(
labelStyle: CoreTextStyle.token(
CoreTextStyles.titleMedium,
color: CoreColor.token(CoreColors.primary),
),
requiredColor: CoreColor.token(CoreColors.tertiary),
requiredIndicatorGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
class FormLabelChainExample extends StatelessComponent {
const FormLabelChainExample({super.key});
@override
Component build(BuildContext context) {
return FormLabel(
label: Text('이메일'),
isRequired: true,
).withStyle(
const CoreFormLabelStyle(
labelStyle: CoreTextStyle.token(
CoreTextStyles.titleMedium,
color: CoreColor.token(CoreColors.primary),
),
requiredColor: CoreColor.token(CoreColors.tertiary),
requiredIndicatorGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
Props#
| 파라미터 | 타입 | 기본값 | 설명 |
|---|---|---|---|
label |
Widget / Component |
required (Flutter) | 라벨 콘텐츠 |
isRequired |
bool |
false |
필수 표시(*) 노출 여부 |
requiredIndicator |
Widget / Component? |
null |
커스텀 필수 표시 (기본: error 색 별표) |
formLabelStyle |
CoreFormLabelStyle? |
null |
chrome / 타이포 단일 진입점 |
스타일 시스템 (Style System)#
CoreFormLabelStyle 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
labelStyle |
CoreTextStyle? |
Nested [CoreTextStyle] slot for the label typography — role + colour.
null
→ the design-system [defaultLabelStyle] (
labelLarge
/ on-surface). A caller that overrides only the colour keeps the default role, and vice versa, because the resolver merges this override on top of [defaultLabelStyle].
|
requiredColor |
CoreColor? |
Override colour applied to the required indicator. |
requiredIndicatorGapStyle |
CoreGapStyle? |
Nested [CoreGapStyle] slot for the gap between the label and the required indicator — forwarded straight to
Gap(gapStyle: …)
.
Gap
runs its own resolve step, so this slot is merged on top of the design-system default in pre-scaling units (the receiving widget owns scaling).
|
사용 가이드라인 (Usage Guidelines)#
✅ Do#
입력 컴포넌트에 접근 가능한 이름을 직접 지정
FormLabel(label: const Text('이메일'), isRequired: true)
TextField(
placeholder: const Text('you@company.com'),
// 접근 가능한 이름은 이 TextField 쪽에서 직접 책임져야 함
)
FormLabel이 그리는 <label>은 for를 emit하지 않고 Flutter에는 대응하는 Semantics 연결조차 없어, 라벨이 어떤 컨트롤과도 연결되지 않습니다. 접근 가능한 이름은 입력 컴포넌트 쪽에서 직접 지정해야 합니다.
❌ Don't#
isRequired 하나로 "필수" 여부가 낭독된다고 가정하지 않기
// ❌ isRequired 는 시각적 별표만 만들 뿐 보조기술에 아무것도 알리지 않음
FormLabel(label: const Text('이메일'), isRequired: true)
isRequired는 시각적 별표만 만들 뿐 aria-required도, "필수"라는 텍스트도 보조기술에 노출하지 않습니다. 필수 여부를 낭독시키려면 입력 컴포넌트(예: FormField의 aria-required) 쪽에 별도로 표기해야 합니다.
접근성 (Accessibility)#
역할 / 시맨틱#
-
Web: 네이티브
<label>요소로 렌더됩니다. 다만for속성을 emit 하지 않습니다 — 컴포넌트가 붙이는 속성은 호출자가 넘긴 것뿐입니다. -
Flutter:
Semantics/CoUISemantics가 전혀 없습니다.DefaultTextStyle.merge→Row로 텍스트만 그립니다.
기본 필수 표시(*)는 양 플랫폼 모두 낭독에서 제외됩니다 — Web 은 <span aria-hidden="true">, Flutter 는
ExcludeSemantics 입니다.
키보드#
처리하는 키가 없습니다. Web 의 <label> 도 클릭을 입력으로 전달하지 못합니다 — for 를 emit 하지 않고,
FormField 안에서도 입력을 감싸지 않고 형제로 배치되기 때문입니다.
포커스#
포커스 관련 동작이 없습니다 — FocusNode / tabindex / 포커스 링 / 트랩 / 복원 모두 없습니다.
스크린 리더#
라벨 텍스트가 읽힙니다. Web 의 <label> 은 존재하지만 어떤 컨트롤과도 연결되어 있지 않아, 컨트롤의 접근 가능한 이름이 아니라 그냥 일반 텍스트로
낭독됩니다.
알려진 제약#
-
for/id연결도, 입력 감싸기도 없어<label>의 시맨틱이 실질적으로 장식입니다. 이 라벨은 입력의 이름이 되지 못하며, Flutter 에는 라벨 연결 수단 자체가 없습니다. 입력의 접근 가능한 이름은 입력 컴포넌트 쪽에서 직접 지정하세요. -
isRequired는 시각적 별표만 만듭니다.aria-required도, "필수"라는 텍스트도 보조기술에 노출되지 않으므로 필수 여부는 입력 자체에 따로 표기해야 합니다. -
커스텀
requiredIndicator는 숨김 처리를 우회합니다. 기본 별표와 달리aria-hidden(Web) /ExcludeSemantics(Flutter) 가 붙지 않아 그대로 낭독됩니다. 장식용 마커라면 호출자가 직접 숨겨야 합니다.