API
Textarea
Multi-line text input.
Installation
pnpm dlx zazz-ui add textareanpx zazz-ui add textareayarn dlx zazz-ui add textareabunx zazz-ui add textareaAlso adds fields, which it depends on. Run zazz-ui init first if the project has no zazz/ folder yet.
Examples
<div data-ui="field">
<label data-field-slot="label" for="f-message">Message</label>
<textarea
data-ui="textarea"
id="f-message"
name="message"
inputmode="text"
placeholder="Your message"
></textarea>
</div>/**
* textarea.css — Textarea ([data-ui~="textarea"])
*
* @layer variables, components
* @requires _layers.css, _variables.css, _properties.css (--_*-resolved, --_focus-shadow), fields.css
* @uses field-sizing: content — auto-grow with text (modern browsers;
* falls back to fixed min/max block-size where unsupported)
* @tokens --ui-textarea-* (@layer variables;
* --ui-textarea-min-h / -max-h default to lh units and are read raw;
* surface colors read the --ui-field-* family directly)
*/
@layer variables {
:root {
--ui-textarea-w: 100%;
--ui-textarea-min-w: 0;
--ui-textarea-min-h: 5lh;
--ui-textarea-max-h: 12lh;
--ui-textarea-p: var(--ui-field-px);
--ui-textarea-font-size: var(--ui-field-font-size);
--ui-textarea-leading: var(--leading-sm);
--ui-textarea-border-width: var(--ui-field-border-width);
--ui-textarea-border-style: var(--ui-field-border-style);
--ui-textarea-border-color: var(--ui-field-border-color);
--ui-textarea-rounded: var(--ui-field-rounded);
--ui-textarea-resize: vertical;
}
}
@layer ui.components {
:where([data-ui~="textarea"]) {
field-sizing: content;
/* dual-mode metrics go through the registered typed pair */
--_w-len: var(--_w-resolved, var(--ui-textarea-w));
--_w-num: var(--_w-resolved, var(--ui-textarea-w));
inline-size: calc(var(--_w-len) + var(--_w-num) * var(--spacing));
--_min-w-len: var(--_min-w-resolved, var(--ui-textarea-min-w));
--_min-w-num: var(--_min-w-resolved, var(--ui-textarea-min-w));
min-inline-size: calc(var(--_min-w-len) + var(--_min-w-num) * var(--spacing));
min-block-size: var(--_min-h-resolved, var(--ui-textarea-min-h));
max-block-size: var(--_max-h-resolved, var(--ui-textarea-max-h));
--_p-len: var(--_p-resolved, var(--ui-textarea-p));
--_p-num: var(--_p-resolved, var(--ui-textarea-p));
padding: calc(var(--_p-len) + var(--_p-num) * var(--spacing));
font-size: var(--_font-size-resolved, var(--ui-textarea-font-size));
line-height: var(--_leading-resolved, var(--ui-textarea-leading));
color: var(--_text-resolved, var(--ui-field-text));
background-color: var(--_bg-resolved, var(--ui-field-bg));
border-width: var(--_border-width-resolved, var(--ui-textarea-border-width));
border-style: var(--_border-style-resolved, var(--ui-textarea-border-style));
border-color: var(--_border-color-resolved, var(--ui-textarea-border-color));
border-radius: var(--_rounded-resolved, var(--ui-textarea-rounded));
resize: var(--ui-textarea-resize);
/* The ring is published to --_focus-shadow so a --shadow utility keeps
it; the transparent outline twin keeps focus visible in forced-colors */
--_ring-offset-width: 0px;
--_ring-width: 0px;
--_focus-in: max(0, -1 * sign(var(--_focus-ring-w, 1px)));
--_ring-fill: color-mix(in oklch, var(--ui-field-ring-color) var(--ring-opacity), transparent);
--_focus-shadow:
0 0 0 calc(var(--_ring-offset-width) * (1 - var(--_focus-in))) var(--ring-offset-shadow-color),
0 0 0 calc((var(--_ring-offset-width) + var(--_ring-width)) * (1 - var(--_focus-in)))
var(--_ring-fill, var(--ring-shadow-color)),
inset 0 0 0 calc(var(--_ring-offset-width) * var(--_focus-in)) var(--ring-offset-shadow-color),
inset 0 0 0 calc((var(--_ring-offset-width) + var(--_ring-width)) * var(--_focus-in))
var(--_ring-fill, var(--ring-shadow-color));
box-shadow: var(--_focus-shadow, 0 0 #0000), var(--_shadow-resolved, 0 0 #0000);
outline: abs(var(--_focus-ring-w, var(--outline-width))) var(--outline-style) transparent;
outline-offset: calc(
var(--outline-offset) - var(--_focus-in) *
(2 * var(--outline-offset) + abs(var(--_focus-ring-w, var(--outline-width))))
);
transition: var(--default-transition);
}
@media (hover: hover) {
:where([data-ui~="textarea"]):hover {
border-color: var(--_border-color-resolved, var(--ui-field-border-color--hover));
background-color: var(--_bg-resolved, var(--ui-field-bg--hover));
}
}
:where([data-ui~="textarea"]):focus-visible {
background-color: var(--_bg-resolved, var(--ui-field-bg--focus-within));
border-color: var(--_border-color-resolved, var(--ui-field-border-color--focus-within));
--_ring-offset-width: var(--ring-offset-width);
--_ring-width: abs(var(--_focus-ring-w, var(--ring-width)));
outline-color: transparent;
}
}
/* an invalid control remaps the --ui-field-* family on itself */
@layer ui.components {
:where([data-ui~="textarea"]):disabled {
opacity: 0.5;
cursor: not-allowed;
}
:where([data-ui~="textarea"]):user-invalid {
--ui-field-bg: color-mix(in oklch, var(--color-destructive) 5%, var(--color-input));
--ui-field-bg--hover: color-mix(in oklch, var(--color-destructive) 10%, var(--color-input));
--ui-field-border-color: var(--color-destructive);
--ui-field-border-color--hover: var(--color-destructive);
--ui-field-border-color--focus-within: var(--color-destructive);
--ui-field-ring-color: var(--color-destructive);
border-color: var(--color-destructive);
}
}Attributes
| Attribute | Kind | Values | Notes |
|---|---|---|---|
data-ui="textarea" | Identity | free value | Identity token in data-ui. |
Requires: fields.
Hooks
Set a hook on :root, on a subtree, or inline on one element. A state hook (--…--hover) themes that state only; the primitive keeps its other states.
| Hook | Default | State |
|---|---|---|
--ui-textarea-border-color | var(--ui-field-border-color) | — |
--ui-textarea-border-style | var(--ui-field-border-style) | — |
--ui-textarea-border-width | var(--ui-field-border-width) | — |
--ui-textarea-font-size | var(--ui-field-font-size) | — |
--ui-textarea-leading | var(--leading-sm) | — |
--ui-textarea-max-h | 12lh | — |
--ui-textarea-min-h | 5lh | — |
--ui-textarea-min-w | 0 | — |
--ui-textarea-p | var(--ui-field-px) | — |
--ui-textarea-resize | vertical | — |
--ui-textarea-rounded | var(--ui-field-rounded) | — |
--ui-textarea-w | 100% | — |