TextField
A text input with a visible label and an optional hint. The label is required: it is what assistive technology reads.
The preview needs JavaScript. The code is in the Code tab.
<template>
<div>
<TextField>
<span slot="label">Email</span>
<span slot="hint">We only use it to sign you in.</span>
</TextField>
<TextField error="Enter your name.">
<span slot="label">Name</span>
</TextField>
</div>
</template>
Installation
npx @pixelscriptio/tessera add TextFieldpnpm exec tessera add TextFieldyarn tessera add TextFieldbunx @pixelscriptio/tessera add TextField- Works with Tessera 0.9.0 or newer.
Copy and paste the code into your project
Put it in
system/components.system/components/TextField.tess <contract> { "name": "TextField", "role": "generic", "description": "A text input with a visible label and an optional hint. The label is required: it is what assistive technology reads.", "since": "0.5.0", "parts": ["root", "label", "input", "hint", "error"], "variants": { "size": ["md", "sm"] // first value is the default }, "states": ["hover", "focus-visible", "disabled"], "slots": { "label": "the visible label, required", "hint": "help under the input" }, "events": { "input": "fired with the new text on every change", "change": "fired with the text when the person leaves the field after changing it" }, "preview": { "slots": { "label": "Email", "hint": "We only use it to sign you in." } } } </contract> <script> const { value, type, placeholder, disabled, invalid, error } = props({ value: '', type: 'text', placeholder: '', disabled: false, invalid: false, error: '', }) // Ids of its own, so the hint and the error can describe the input however many fields there are. const uid = `t-textfield-${Math.random().toString(36).slice(2, 9)}` // The field owns what is typed, starts from the prop and follows it when it changes. const text = state(value.value) effect(() => { text.value = value.value }) function typed(event) { emit('input', event.target.value) } function committed(event) { emit('change', event.target.value) } </script> <template> <label class="root"> <span class="label"><slot name="label" /></span> <input class="input" :type="type" :placeholder="placeholder" :disabled="disabled" :aria-invalid="invalid || error ? 'true' : null" :aria-describedby="uid + '-hint ' + uid + '-error'" bind:value="text" @input="typed($event)" @change="committed($event)" /> <span class="hint" :id="uid + '-hint'"><slot name="hint" /></span> <span class="error" :id="uid + '-error'" aria-live="polite">{error}</span> </label> </template> <style> .root { display: flex; flex-direction: column; gap: $space.1; color: $color.text.default; font-family: var(--t-font-family-sans); font-size: $font.size.sm; } .label { font-size: $font.size.sm; font-weight: $font.weight.bold; } .input { padding: $space.2 $space.3; border: 1px solid $color.border.strong; border-radius: $radius.md; background: $color.surface.default; color: $color.text.default; font: inherit; transition-duration: $motion.duration.fast; &:hover:not(:disabled) { border-color: $color.text.default; } &:focus-visible { outline: 2px solid $color.focus.ring; outline-offset: 2px; } &:disabled { opacity: $opacity.disabled; cursor: not-allowed; } &[aria-invalid='true'] { border-color: $color.action.danger.text; } } .root[data-size='sm'] .input { padding: $space.1 $space.2; font-size: $font.size.sm; } .hint { color: $color.text.muted; font-size: $font.size.sm; } .error { color: $color.action.danger.text; font-size: $font.size.sm; } .hint:empty, .error:empty { display: none; } </style>Check your design tokens
Your design system needs these.
tessera addreports the ones that are missing; by hand, runnpx @pixelscriptio/tessera check.color.action.danger.textcolor.border.strongcolor.focus.ringcolor.surface.defaultcolor.text.defaultcolor.text.mutedfont.size.smfont.weight.boldmotion.duration.fastopacity.disabledradius.mdspace.1space.2space.3
Usage
Using TextField
A text input with a visible label and an optional hint.
- The label is required. It is what assistive technology reads. Do not use the placeholder as the label.
- Use the
hintslot for help, and theerrorprop for what is wrong. The error is announced when it appears, is read with the field, and turns the border red. Settingerroralso marks the field invalid. Setinvalidalone when the reason is shown elsewhere. typeis any text-like input type:text,email,password,search,url,tel.inputfires on every change with the new text, andchangefires when the person leaves the field.
The preview needs JavaScript. The code is in the Code tab.
<template>
<div>
<TextField>
<span slot="label">Email</span>
<span slot="hint">We only use it to sign you in.</span>
</TextField>
<TextField error="Enter your name.">
<span slot="label">Name</span>
</TextField>
</div>
</template>
API reference
Variants
| Variant | Values |
|---|---|
size | md default sm |
Slots
| Slot | Content |
|---|---|
label | the visible label, required |
hint | help under the input |
Events
| Event | When |
|---|---|
input | fired with the new text on every change |
change | fired with the text when the person leaves the field after changing it |
Anatomy
| Role | generic |
| Parts | root label input hint error |
| States | hover focus-visible disabled |
| Since | 0.5.0 |
Design tokens it uses
Your design system needs these. tessera add checks that it has them, and can add the ones it lacks.
color.action.danger.text color.border.strong color.focus.ring color.surface.default color.text.default color.text.muted font.size.sm font.weight.bold motion.duration.fast opacity.disabled radius.md space.1 space.2 space.3
Checksum
cc179afa8c4c5ae16fe908c6937edf5dad05fc5f2c9704f183a7af62417e41e4