# 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.40.0/src/tokens/tokens.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.40.0/src/components/css/label/label.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.40.0/src/components/css/input/input.css">
<!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.40.0/dist/lotek.css -->
```

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


<label class="lt-label" data-required="symbol" for="fixer">Fixer's address</label>
<input class="lt-input" id="fixer" type="email" required />


<label class="lt-label" data-required="text" for="budget">Budget</label>
<input class="lt-input" id="budget" type="text" inputmode="numeric" required />


<label class="lt-label" data-optional="" for="entry">Entry point</label>
<input class="lt-input" id="entry" type="text" />


<label class="lt-label" aria-disabled="true" for="reference">Reference</label>
<input class="lt-input" id="reference" 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="codename">Codename</label>
<input {...lt.input({ type: "text" })} id="codename" />
```

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>("#fixer-label")
if (!label) throw new Error("element not found")


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

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>("#fixer")


const field = lt.field({ id: "fixer", 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.

**kotlinx.html**

```kotlin
// Once for the whole app, in the page template: every stylesheet, from the WebJar.
head { link(rel = "stylesheet", href = LotekWebJar.CSS) }
```

On a Kotlin or Java server, the same with kotlinx.html and `lo-tek-kotlinx-html`. The builder functions are in `Lt`, with an enum for each list of values:

```kotlin
import kotlinx.html.*
import no.lotek.*
import no.lotek.InputType
import no.lotek.html.lt


fun FlowContent.order() {
    label { lt(Lt.label()); htmlFor = "codename"; +"Codename" }
    input { lt(Lt.input(type = InputType.TEXT)); id = "codename" }
    label { lt(Lt.label(required = RequiredMarker.SYMBOL)); htmlFor = "fixer"; +"Fixer's address" }
    input { lt(Lt.input(type = InputType.EMAIL)); id = "fixer"; required = true }
    label { lt(Lt.label(required = RequiredMarker.TEXT)); htmlFor = "budget"; +"Budget" }
    input { lt(Lt.input(type = InputType.TEXT)); id = "budget"; attributes["inputmode"] = "numeric"; required = true }
    label { lt(Lt.label(optional = true)); htmlFor = "entry"; +"Entry point" }
    input { lt(Lt.input(type = InputType.TEXT)); id = "entry" }
    label { lt(Lt.label(disabled = true)); htmlFor = "reference"; +"Reference" }
    input { lt(Lt.input(type = InputType.TEXT)); id = "reference"; disabled = true }
}
```

| 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="fixer">Fixer's address</label>
<input class="lt-input" id="fixer" type="email" required aria-describedby="fixer-help" />
<p class="lt-help-text" id="fixer-help">The board writes to the fixer, never to the crew.</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.
