TextField
A single line of text with a label, a hint and validation that waits until the user is done, then clears as soon as the value is fixed.
Usage
Bind the value and give it a label. The input receives every other
attribute you pass, such as name, autocomplete, placeholder and events, while class and style apply to the
whole field.
Receipts go to this address
At least 8 characters, with a digit
Type something, then leave the field.
<script>
import { TextField } from 'sveltier';
let email = $state('');
</script>
<TextField
label="Email"
type="email"
name="email"
autocomplete="email"
hint="Receipts go to this address"
required
bind:value={email}
/>Validation
A field's message comes from three places, checked in this order:
- The HTML constraints you already know:
required,minlength,maxlength,pattern, andtype="email"or"url". Their messages come from the locale, so they read the same in every browser and translate with your app. rules: functions that returntrueor the message to show. They run in order and stop at the first message. Like the constraints, they skip an empty field that is not required.error: a message from outside the field, usually the answer of your server. It shows at once, and it never stops the form from being submitted again.
A message appears when the user leaves a field they have changed, not while they tab through the
form. Once it is shown, it follows every keystroke, so fixing the value clears it at once. Set validateOn to "input" to check from the first change, or to "submit" to wait for the form. Inside a plain <form>, the
browser also refuses to submit an invalid field, with the same words.
Lowercase letters, digits and _. Try “ada”.
<script>
import { TextField } from 'sveltier';
// The result of a SvelteKit form action, with the server's own errors.
let { form } = $props();
let username = $state('');
const rules = [
(value) => /^[a-z0-9_]+$/.test(value) || 'Use lowercase letters, digits and _',
(value) => !value.startsWith('_') || 'Start with a letter or a digit'
];
</script>
<TextField
label="Username"
name="username"
required
minlength={3}
maxlength={20}
{rules}
error={form?.errors?.username}
bind:value={username}
/>Variants
Fields take five of the shared variants: outlined (the default) draws a border, tonal a wash with a rule under it, elevated a raised surface for a
field over an image, text only the rule, and plain nothing, for a
field inside another component. color is the accent of the focused field; an invalid
field turns to the error colour.
Size and density
A field is as tall as a Button of the same size and density, so they
line up in a row. The label keeps the theme's label style at every size.
Icons and actions
prepend and append put content inside the box: an icon, a prefix, or a button.
A press anywhere else in the box focuses the input.
<script>
import { Button, Icon, TextField } from 'sveltier';
let visible = $state(false);
</script>
<TextField label="Search" type="search" variant="elevated">
{#snippet prepend()}<Icon path={SEARCH} />{/snippet}
</TextField>
<TextField label="Password" type={visible ? 'text' : 'password'} autocomplete="current-password">
{#snippet append()}
<Button variant="text" size="sm" onclick={() => (visible = !visible)}>
{visible ? 'Hide' : 'Show'}
</Button>
{/snippet}
</TextField>Accessibility
- The label is a
<label>for the input. Without a visible label, name the input witharia-label. - The hint, or the error in its place, describes the input, and an invalid field is marked
aria-invalid. Anaria-describedbyof your own is kept alongside. - An error that appears after the user has moved on is announced politely.
requiredadds an asterisk that screen readers skip: the input already says it is required.- Text is at least 16 px on touch screens, where smaller text makes iOS zoom into the page.
API
| Name | Type | Default | Description |
|---|---|---|---|
variant | 'outlined' | 'tonal' | 'elevated' | 'text' | 'plain' | 'outlined' | How the box is drawn. |
color | Color | 'primary' | The accent of the focused field. An invalid field uses error. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Height and text size, matching a Button of the same size. |
density | 'compact' | 'default' | 'comfortable' | 'default' | Multiplies the height and padding, never the text. |
rounded | boolean | 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full' | true | Corner rounding. true keeps the theme's radius. |
disabled | boolean | false | Mutes the field and disables its control. |
label | string | – | The visible label, linked to the control. Without it, name the control with aria-label. |
hint | string | – | Help under the field. An error replaces it. |
error | FieldError | – | An error from outside the field, such as the server's answer: a message, a list of which
the first is shown, or true for an invalid state described elsewhere. |
prepend | Snippet | – | Content at the start of the box, usually an icon. |
append | Snippet | – | Content at the end of the box: an icon, a unit or a button. |
value | string | – | The text. Bindable. |
type | 'text' | 'email' | 'password' | 'search' | 'tel' | 'url' | 'text' | The kind of text: it picks the keyboard and autofill, and email and url are checked. |
rules | readonly Rule<string>[] | – | Checks run in order after the HTML constraints. The first message is shown. |
validateOn | 'blur' | 'input' | 'submit' | – | When the message shows. Defaults to the form's setting, else 'blur'. |
required | boolean | false | The field must not be empty. Adds an asterisk to the label. |
readonly | boolean | false | The text can be read, selected and copied but not changed. |
style | string | null | – | Inline style of the field's root element. |
class | ClassValue | null | – | Classes added after the component's own: a string, an array or an object. |
ref | HTMLInputElement | null | – | The root element, bindable with bind:ref. |