@k4k3ru/design-system-text-field
v1.1.0
Published
Accessible native text fields for the k4k3ru design system
Readme
@k4k3ru/design-system-text-field
Native HTML text fields inspired by Material Design 3. The official Material Web documentation informs the filled/outlined variants, floating labels and supporting/error text. K4K3RU tokens take precedence over Material dimensions, palette and typography. This is a CSS component, not a wrapper around Material Web. No runtime dependency or component JavaScript is required.
Usage
Build the local package with npm run build:text-field from the repository root.
A consumer can reference web/components/text_field using a relative file:
dependency. The package exports dist/style.css; rebuild after source changes.
@import "@k4k3ru/design-system-tokens/style.css";
@import "@k4k3ru/design-system-text-field/style.css";<div class="text-field text-field--outlined">
<div class="text-field__control">
<input class="text-field__input" id="email" name="email" type="email"
placeholder=" " autocomplete="email" required aria-describedby="email-help">
<label class="text-field__label" for="email">Email address *</label>
</div>
<p class="text-field__support" id="email-help">Required · Use your account email.</p>
</div>Use text-field--filled for a filled container and bottom indicator. Outlined is
the default. The input must immediately precede its label inside the control.
Always provide a unique id, matching label for, and a placeholder (a single
space is enough). CSS uses :placeholder-shown to track values without event
listeners, including programmatic values and form reset. Real hint placeholders
appear on focus. The label remains the accessible name.
Supported controls: input types text, email, password, search, tel,
url, and textarea. Multiline labels always float, so scrolling text cannot
hide the label. Use rows and native vertical resizing for multiline input.
Other input types (date, file, range, checkbox, etc.) are outside this component.
text-field--floating can pin a label above the input when required by a consumer.
Native disabled, including a parent disabled fieldset, and readonly retain
browser behavior. Readonly fields remain focusable, selectable and submitted;
disabled fields do not. Use autocomplete, inputmode, maxlength, required
and pattern on the native control as appropriate. No automatic password reveal,
clear button, icon slots, character counter or validation logic is included.
Populated fields retain the focus-colored border and label after blur. Clearing the value restores the empty state. Error and disabled states take precedence. Typing or browser autofill does not add a background tint; autofill is painted with the normal surface of the selected variant. Focus outlines remain visible.
Validation and accessibility
Validation timing is owned by the application. Fields are not colored red merely
because an empty required value is initially invalid. Use native constraint
validation or application validation, then set aria-invalid="true" on the input
and associate a visible .text-field__error using aria-describedby. Remove the
attribute and hide the error when resolved. Color alone is not an error message.
<input class="text-field__input" id="code" name="code" type="text"
placeholder=" " inputmode="numeric" aria-invalid="true" aria-describedby="code-error">
<label class="text-field__label" for="code">Verification code</label>
<!-- Place outside text-field__control, inside text-field: -->
<p class="text-field__error" id="code-error">Enter the six-digit code.</p>Use visible required instructions and the native required attribute; CSS does
not synthesize an asterisk. The demo includes manual error timing, recovery and
reset. Long labels are visually ellipsized while preserving their full accessible
name; prefer concise labels and place longer instructions in supporting text.
Focus, reduced motion, RTL positioning and forced-colors styles are supported.
Manual assistive-technology verification is still recommended for consuming forms.
Tokens and customization
Public component properties override shared token mappings. Shared tokens override
standalone fallbacks. Properties starting with --_text-field- are private.
| Public property | Shared token |
| --- | --- |
| --text-field-background | --color-surface |
| --text-field-filled-background | --color-surface-container-highest |
| --text-field-color, --text-field-muted-color | --color-on-surface |
| --text-field-border-color | --color-outline |
| --text-field-focus-color | --color-info (no primary token currently exists) |
| --text-field-error-color | --color-error |
| --text-field-height | --control-height-large (minimum; content may grow) |
| --text-field-radius | --control-radius-small |
| --text-field-font-size, --text-field-line-height | Body large typography |
| --text-field-label-font-size, --text-field-label-line-height | Body small typography |
| --text-field-support-font-size, --text-field-support-line-height | Body small typography |
| --text-field-gap | --control-gap-small |
| --text-field-motion-duration, --text-field-motion-easing | --motion-standard, --easing-standard |
--text-field-padding-inline and --text-field-padding-block control spacing.
The outlined floating label uses --text-field-background to cover the border;
set it to the surrounding surface when embedding the field on another surface.
The shared outline palette is intentionally preserved; applications requiring
stronger non-text contrast can override --text-field-border-color.
.account-form {
--text-field-background: var(--color-surface-container-lowest);
--text-field-focus-color: var(--color-success);
}Without tokens, standalone light/dark fallbacks apply. With or without tokens,
data-theme="light" or data-theme="dark" on <html> overrides OS preference.
Modern browsers supporting :has(), :is(), :placeholder-shown and
color-mix() are required for the complete presentation.
Preview and verification
npm run build:text-field
npm run typecheck
python3 -m http.server 5180 --bind 127.0.0.1Open /web/components/text_field/example/ for both variants, native input types,
error/disabled/readonly states, textarea, theme switching and manual validation.
The demo never transmits or stores field values.
Package CSS and browser interaction checks are described in VERIFICATION.md.
License
MIT
Smaller size
Use text-field--smaller on the component root. Height, padding and input text; preserves floating labels and support text.
See shared sizing guidance and examples.
In text-field--smaller, empty, unfocused labels inside the control use the
input typography (16px with the shared tokens), matching smaller Select Box
selected text. Floating labels use extra-small label tokens (12px text,
16px line height), including on focus, after input, on textareas and explicit
floating fields. Input text and support text retain their existing sizes.
This also applies to filled fields; default-sized fields are unchanged.
