# Label

> A label for form fields, with marking of required and optional. A CSS component.

The right typography on `<label>`, and one consistent way to mark required and optional fields. If you are setting up a whole field, [Field](/components/field.md) is usually simpler. It sets `for`, `id` and `aria-describedby` for you.

## How to use it

**Plain HTML**

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/label/label.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/input/input.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css -->
```

```html
<label class="lt-label" for="name">Full name</label>
<input class="lt-input" id="name" type="text" />


<label class="lt-label" data-required="symbol" for="email">Email address</label>
<input class="lt-input" id="email" type="email" required />


<label class="lt-label" data-required="text" for="phone">Phone number</label>
<input class="lt-input" id="phone" type="tel" required />


<label class="lt-label" data-optional="" for="address">Address</label>
<input class="lt-input" id="address" type="text" />


<label class="lt-label" aria-disabled="true" for="org-number">Organisation number</label>
<input class="lt-input" id="org-number" type="text" disabled />
```

**TypeScript**

```ts
import "@lo-tek/interfaces/tokens.css"
import "@lo-tek/interfaces/label.css"
import "@lo-tek/interfaces/input.css"
```

`lt` is used in two ways, and which one depends on whether you create the element or find it.

**If you create the markup,** spread the attributes in. That is the way in React, Astro and anything else that renders:

```tsx
import { lt } from "@lo-tek/interfaces/react"


<label {...lt.label()} htmlFor="name">Full name</label>
<input {...lt.input({ type: "text" })} id="name" />
```

The import is from `/react` here, since the block is JSX. From there the keys are `className` and `htmlFor`. In Astro and anything else without React, import `@lo-tek/interfaces` and you get `class` and `for`.

**If the element is already there,** set them on it. That is the way when you enhance HTML a server or a template has sent:

```ts
import { lt } from "@lo-tek/interfaces"


const label = document.querySelector<HTMLLabelElement>("#email-label")
if (!label) throw new Error("element not found")


lt.setAttributes(label, lt.label({ required: "symbol" }))
label.htmlFor = "email"
```

You set `for` yourself. The function returns only LO-TEK’s own attributes.

If you are setting up a whole field, [`lt.field`](/components/field.md) does both the marking and the wiring to the control:

```ts
const input = document.querySelector<HTMLInputElement>("#email")


const field = lt.field({ id: "email", required: "symbol" })


lt.setAttributes(label, field.label)
lt.setAttributes(input, lt.input({ type: "email" }), field.control)
if (input) input.required = true
```

`required: "symbol"` gives only the asterisk. That the field has to be filled in is said by `required` on the field itself.

| Attribute | Effect |
| - | - |
| *(omitted)* | An ordinary label |
| `data-required="symbol"` | `*` in the danger colour |
| `data-required="text"` | `(required)` in the danger colour |
| `data-optional=""` | `(optional)` in a muted colour |
| `aria-disabled="true"` | Muted text colour |

Choose one of `data-required` and `data-optional` and stick to it throughout the form. If you set both, the system shows only one: they are the same `::after`, and the builder function drops `data-optional` when the field is required.

## Together with a field

`for` has to match the `id` of the field. Without the wiring the label is not read out when the field gets focus, and a click on the text does not move focus there.

**Plain HTML**

```html
<label class="lt-label" data-required="symbol" for="email">Email address</label>
<input class="lt-input" id="email" type="email" required aria-describedby="email-help" />
<p class="lt-help-text" id="email-help">We use the address to send you a receipt.</p>
```

## Classes you can style

| Class | What it is |
| - | - |
| `.lt-label` | The label. The markers are added with `::after`. |

The marker behind `data-required` and `data-optional` is text in `::after`, and the text is read from a variable. It can then be replaced, or translated, without changing the markup:

| Variable | Default |
| - | - |
| `--lt-label-required-symbol` | `" *"` |
| `--lt-label-required-text` | `" (required)"` |
| `--lt-label-optional-text` | `" (optional)"` |

```css
:root:lang(nb) {
  --lt-label-required-text: " (påkrevd)";
  --lt-label-optional-text: " (valgfri)";
}
```

The variables also apply to `.lt-legend` in [Fieldset](/components/fieldset.md). See [Translation](/translation.md).

See [Customising](/customising.md) for how the layer works.

## Accessibility

- `data-required` is only visual. Set `required` on the field itself, or the screen reader will not know it has to be filled in.
- The asterisk and “(required)” are added with `::after`. Content in `::after` counts towards the field’s name, so a screen reader may read it after the label. It is `required` on the field that says it has to be filled in.
- Never hide the label completely. If you need it gone visually, use `.lt-sr-only` from `sr-only.css` rather than `placeholder`, which disappears as soon as the user types.
