---
title: Label
description: Form label with required indicator
visibility: guest
draft: false
---

# Label

A minimal label component for form fields with optional required indicator.

## Basic Usage

:::preview{title="A label bound to its input"}
<x-wirekit::label for="name">Full Name</x-wirekit::label>
<x-wirekit::input name="name" />
:::

## Required Indicator

:::preview{title="A required field, marked on the label"}
<x-wirekit::label for="email" required>Email</x-wirekit::label>
<x-wirekit::input name="email" type="email" />
:::

Displays a red asterisk (`*`) using the `--color-wk-danger-text` CSS variable. The asterisk includes `aria-hidden="true"` since it is purely decorative.

## Narrow Column — Label Above Field

When the form lives in a sidebar, modal, or mobile-narrow column, place the label directly above the input. The label inherits the input's full width without competing for horizontal space. This is the default layout used by `<x-wirekit::input label="…">` and every other WireKit form component when you pass the `label` prop.

:::preview{title="Stacked label + input in a 16rem column"}
<x-wirekit::stack gap="md" style="max-width: 16rem">
    <div>
        <x-wirekit::label for="username" required>Username</x-wirekit::label>
        <x-wirekit::input name="username" placeholder="jane.doe" />
    </div>
    <div>
        <x-wirekit::label for="newsletter">Newsletter</x-wirekit::label>
        <x-wirekit::select name="newsletter">
            <option>Weekly digest</option>
            <option>Daily updates</option>
            <option>None</option>
        </x-wirekit::select>
    </div>
</x-wirekit::stack>
:::

## Horizontal Form — Inputs Aligned on a Vertical Line

For wider forms (settings pages, billing-address screens), pair each label with its input on a single row and pin the labels to a fixed-width column so every input starts at the same horizontal position. CSS Grid with `grid-template-columns: <label-col> 1fr` keeps the alignment robust across long labels and varying input widths:

:::preview{title="Billing address — labels left, inputs aligned on a vertical line"}
<form style="display: grid; grid-template-columns: 9rem 1fr; gap: 0.75rem 1rem; align-items: center; max-width: 36rem;">
    <x-wirekit::label for="ba-name" required>Full name</x-wirekit::label>
    <x-wirekit::input name="ba-name" placeholder="Jane Doe" />

    <x-wirekit::label for="ba-company">Company</x-wirekit::label>
    <x-wirekit::input name="ba-company" placeholder="Acme Inc." />

    <x-wirekit::label for="ba-street" required>Street &amp; number</x-wirekit::label>
    <x-wirekit::input name="ba-street" placeholder="Hauptstraße 12" />

    <x-wirekit::label for="ba-zip" required>ZIP / city</x-wirekit::label>
    <x-wirekit::input name="ba-zip" placeholder="10115 Berlin" />

    <x-wirekit::label for="ba-country" required>Country</x-wirekit::label>
    <x-wirekit::select name="ba-country">
        <option>Germany</option>
        <option>Austria</option>
        <option>Switzerland</option>
    </x-wirekit::select>

    <x-wirekit::label for="ba-vat">VAT ID</x-wirekit::label>
    <x-wirekit::input name="ba-vat" placeholder="DE123456789" />
</form>
:::

The `9rem` label column is the smallest width that holds the longest label (`Street & number`) without wrapping; raise to `10–12rem` if your form has longer field names. Switch to a single-column stack on narrow viewports with `@media (max-width: 480px) { form { grid-template-columns: 1fr; } }` so the labels don't get cramped — the same layout collapses gracefully to the stacked pattern shown above.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `for` | string\|null | `null` | The `id` of the associated form element |
| `required` | bool | `false` | Shows a required indicator (`*`) |
| `scope` | string\|null | `null` | Scoped personalization name |

## Accessibility

The label component renders a native `<label>` element — the most important accessibility primitive for form fields.

- **`for` attribute** — Always set the `for` prop to the `id` of the associated input. This creates a programmatic association so screen readers announce the label when the input receives focus, and clicking the label focuses the input.
- **Required indicator** — The red asterisk (`*`) includes `aria-hidden="true"` because it is purely visual. Screen readers should not announce "asterisk" — instead, mark required fields with the native `required` attribute on the input itself, which assistive technology announces as "required".
- **Implicit vs. explicit labeling** — WireKit form components (Input, Textarea, Select, etc.) handle labeling automatically when you pass the `label` prop — they render `<x-wirekit::label for="{id}">` internally. Use the standalone Label component only when building custom form layouts.

## Keyboard Interaction

This component is purely presentational and does not respond to keyboard input.

## Design Tokens

| Token | Used for |
| --- | --- |
| `--font-wk-sans` | Label font family |
| `--font-wk-body-weight` | Label font weight |
| `--font-wk-letter-spacing` | Letter spacing |
| `--text-wk-md` | Label font size |
| `--color-wk-text` | Label text |
| `--color-wk-danger-text` | Required indicator (`*`) |

## Further Reading

- [MDN: `<label>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
- [MDN: Labels and form controls](https://developer.mozilla.org/en-US/docs/Learn/Forms/How_to_structure_a_web_form#the_label_element)
- [WebAIM: Form Labels](https://webaim.org/techniques/forms/controls) — accessibility guidance
