Textarea
The same look and states as Input, for answers longer than one line.
How to use it
Section titled “How to use it”<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/textarea/textarea.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/label/label.css"><!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css --><label class="lt-label" for="reason">Reason</label><textarea class="lt-textarea" id="reason" rows="3"placeholder="Write a short reason"></textarea>
<label class="lt-label" for="message">Message to the caseworker</label><textarea class="lt-textarea" id="message"data-state="success">I am moving to a new address on 1 June.</textarea>
<label class="lt-label" for="answer">Detailed answer</label><textarea class="lt-textarea" id="answer"data-state="invalid" aria-invalid="true">Too short</textarea>
<label class="lt-label" for="note">Note</label><textarea class="lt-textarea" id="note"disabled>The case is closed and cannot be changed.</textarea>import "@lo-tek/interfaces/tokens.css"import "@lo-tek/interfaces/textarea.css"import "@lo-tek/interfaces/label.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"
<textarea {...lt.textarea({ state: "invalid" })} id="reason" rows={3} />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, type FieldState } from "@lo-tek/interfaces"
const field = document.querySelector<HTMLTextAreaElement>("#reason")if (!field) throw new Error("element not found")
field.addEventListener("blur", () => { const state: FieldState = field.value.trim().length >= 20 ? "success" : "invalid"
lt.setAttributes(field, lt.textarea({ state }))})state is the same type as in Input and Select, so the value can be passed between them. lt.setAttributes clears the state from the previous call, so the field does not stay red after the error is fixed.
data-state | Used for |
|---|---|
| (omitted) | Normal state |
invalid | Validation has failed |
success | The content is confirmed valid |
data-state is colour. Screen readers need aria-invalid="true" as well, or Field, which sets both.
Classes you can style
Section titled “Classes you can style”| Class | What it is |
|---|---|
.lt-textarea | The field. The state comes from data-state. |
| Variable | Default |
|---|---|
--lt-textarea-min-height | calc(var(--lt-spacing-4) * 5) |
--lt-textarea-padding | var(--lt-spacing-2) var(--lt-spacing-3) |
--lt-textarea-radius | var(--lt-spacing-1) |
--lt-textarea-min-height is a minimum height, not a fixed height. rows works above it, and the user can still drag the field taller. With the default font and padding the minimum height is a little under three rows, so rows="1" and rows="2" give the same field, and only rows="3" is taller. If rows alone should decide the height, set --lt-textarea-min-height: 0. The width is locked, since the class sets resize: vertical.
See Customising for how the variables and the layer work.
Accessibility
Section titled “Accessibility”- Every field needs a visible
<label>withforpointing to theid. - If the field has an upper limit, say so in the help text before the user types.
maxlengthalone blocks typing without explaining why. - If you use a character counter, put it in an element with
aria-live="polite"and let it announce only when the limit is near. Otherwise it interrupts the reading on every keystroke. - Do not turn off
resize. It is often the only way the user gets an overview of a long text.