Label
The right typography on <label>, and one consistent way to mark required and optional fields. If you are setting up a whole field, Field is usually simpler. It sets for, id and aria-describedby for you.
How to use it
Section titled “How to use it”<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 --><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 />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:
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:
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 does both the marking and the wiring to the control:
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 = truerequired: "symbol" gives only the asterisk. That the field has to be filled in is said by required on the field itself.
// 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:
import kotlinx.html.*import no.lotek.*import no.lotek.InputTypeimport 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
Section titled “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.
The board writes to the fixer, never to the crew.
<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
Section titled “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)" |
:root:lang(nb) { --lt-label-required-text: " (påkrevd)"; --lt-label-optional-text: " (valgfri)";}The variables also apply to .lt-legend in Fieldset. See Translation.
See Customising for how the layer works.
Accessibility
Section titled “Accessibility”data-requiredis only visual. Setrequiredon 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::aftercounts towards the field’s name, so a screen reader may read it after the label. It isrequiredon the field that says it has to be filled in. - Never hide the label completely. If you need it gone visually, use
.lt-sr-onlyfromsr-only.cssrather thanplaceholder, which disappears as soon as the user types.