Input

If web applications didn't need inputs, computers wouldn't have keyboards.

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>Full name</Label>
	<Input name="full_name" />
</Field>

Component API

PropDefaultDescription
Input extends the Headless UI <Input> component
disabledfalseWhether or not to disable the input.
invalidfalseWhether or not the input has a validation error.
name-The name to use when submitting an HTML form.
defaultValue-The initial value for the input.
value-The controlled value of the input.
onChange-Handler to call when the input value changes.
Field extends the Headless UI <Field> component
disabledfalseWhether or not to disable the entire field.
Label extends the Headless UI <Label> component
This component does not expose any component-specific props.
Description extends the Headless UI <Description> component
This component does not expose any component-specific props.
ErrorMessage extends the Headless UI <Description> component
This component does not expose any component-specific props.

Examples

Basic example

Use the Input component on its own to render a standalone input without an associated Label component:

<script>
	import { Input } from '$lib/components/input';
</script>

<Input aria-label="Full name" name="full_name" />

Make sure to provide an aria-label for assistive technology, or connect the Input to your own <label> element using an id.

With label

Wrap a Label and Input with the Field component to automatically associate them using a generated ID:

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>Full name</Label>
	<Input name="full_name" />
</Field>

With description

Use the Description component to add a description above or below your Input:

Use the name you'd like people to see in their cart.

<script>
	import { Description, Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>Product name</Label>
	<Description>Use the name you'd like people to see in their cart.</Description>
	<Input name="product_name" />
</Field>

With icon

Wrap an icon and Input with the InputGroup component to render an input with an icon:

<script>
	import { Input, InputGroup } from '$lib/components/input';
	import HeroiconsMagnifyingGlass16Solid from 'virtual:icons/heroicons/magnifying-glass-16-solid';
</script>

<InputGroup>
	<HeroiconsMagnifyingGlass16Solid />
	<Input name="search" placeholder="Search&hellip;" aria-label="Search" />
</InputGroup>

The InputGroup component is designed to work best with 16×16 icons.

Setting the type

Use the type prop to set the input type to any supported text input type:

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>Your website</Label>
	<Input type="url" name="url" />
</Field>

The supported types are email, number, password, search, tel, text, url, date, datetime-local, month, time, and week.

Disabled state

Add the disabled prop to the Field component to disable an Input and the associated Label:

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field disabled>
	<Label>Full name</Label>
	<Input name="full_name" />
</Field>

You can also disable an input outside of a Field by adding the disabled prop directly to the Input itself.

Validation errors

Add the invalid prop to the Input component to indicate a validation error, and render the error using the ErrorMessage component:

This field is required.

<script>
	import { ErrorMessage, Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>Full name</Label>
	<Input name="full_name" invalid={errors.has('full_name')} />
	{#if errors.has('full_name')}
		<ErrorMessage>{errors.get('full_name')}</ErrorMessage>
	{/if}
</Field>

Constraining width

Use the class prop on the Input component to make layout adjustments like adjusting the max-width:

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
</script>

<Field>
	<Label>CVC</Label>
	<Input class="max-w-[6rem]" name="cvc" pattern="[0-9]*" />
</Field>

Be aware that the class prop is a sharp knife — make sure to only add classes that don't conflict with classes the component already includes or you'll get unexpected results.

With custom layout

Use the unstyled Field component from @headlessui/react directly instead of the styled Field component to implement a custom layout:

<script>
	import { Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';
	import * as Headless from '@headlessui/react';
</script>

<Headless.Field class="flex items-center justify-center gap-6">
	<Label>Full name</Label>
	<Input name="full_name" class="max-w-48" />
</Headless.Field>

Using the unstyled Field component will ensure important accessibility features are still handled for you like generating IDs and associating elements using aria-* attributes.

Controlled component

Use the normal value and onChange props to use the Input component as a controlled component:

<script>
	import { Field, Label } from '$lib/components/fieldset';
	import { Input } from '$lib/components/input';

	let name = $state('');
</script>

<Field>
	<Label>Full name</Label>
	<Input name="full_name" bind:value={name} />
</Field>