Skip to content
Inputs

Field

Field — the label, the help line and the error, around any control.

Walkthrough

1. Basic

A label, the control, a line of help. The control stays bare — the field gives it its id, its description and its state.

We only use this for billing.

<script lang="ts">	import { Field, Input } from 'omaris';​	let email = $state('');</script>​<Field class="w-80 max-w-full" label="Work email" description="We only use this for billing.">	<Input type="email" placeholder="you@example.com" bind:value={email} /></Field>

2. Validation

error marks the field invalid and opens the error row: it grows from nothing and fades in, so the form below slides rather than jumps. It is announced politely — after the person stops typing, not over them.

Where the menu lives.

<script lang="ts">	import { Field, Input } from 'omaris';​	let slug = $state('my store');	const error = $derived(		/^[a-z0-9-]*$/.test(slug) ? undefined : 'Lowercase letters, digits and dashes only.'	);</script>​<div class="flex w-80 max-w-full flex-col gap-4">	<Field label="Store address" description="Where the menu lives." {error} required>		<Input bind:value={slug} prefix="rasil.app/" />	</Field>	<Field label="Display name">		<Input placeholder="The name on the menu" />	</Field></div>

3. Horizontal

horizontal puts the label and its help at the start and the control at the end — the settings row a switch or a checkbox wants.

A sound and a banner for each new order.

Every Sunday morning.

<script lang="ts">	import { Field, Switch, Checkbox, Divider } from 'omaris';​	let alerts = $state(true);	let digest = $state(false);</script>​<div class="flex w-96 max-w-full flex-col gap-4">	<Field		orientation="horizontal"		label="Order alerts"		description="A sound and a banner for each new order."	>		<Switch bind:checked={alerts} />	</Field>	<Divider />	<Field orientation="horizontal" label="Weekly digest" description="Every Sunday morning.">		<Checkbox bind:checked={digest} />	</Field></div>

4. Any control

One wrapper for every control. A select, a number, a slider and a radio group each pick up the label, the help and the state — a group is named by the label rather than pointed at by it.

Up to twelve at one table.

<script lang="ts">	import { Field, Select, NumberInput, Slider, RadioGroup, Radio } from 'omaris';​	let branch = $state('');	let guests = $state<number | null>(2);	let spice = $state(30);	let seating = $state('inside');</script>​<div class="flex w-80 max-w-full flex-col gap-5">	<Field label="Branch" required error={branch ? undefined : 'Pick the branch it ships from.'}>		<Select			bind:value={branch}			placeholder="Choose one"			options={[				{ value: 'erbil', label: 'Erbil' },				{ value: 'duhok', label: 'Duhok' }			]}		/>	</Field>	<Field label="Guests" description="Up to twelve at one table.">		<NumberInput bind:value={guests} min={1} max={12} />	</Field>	<Field label="Spice">		<Slider bind:value={spice} />	</Field>	<Field label="Seating">		<RadioGroup bind:value={seating} orientation="horizontal">			<Radio value="inside" label="Inside" />			<Radio value="terrace" label="Terrace" />		</RadioGroup>	</Field></div>

5. Overridden

The control's own props win over the field's, and classes reaches every part. Name the control's id on the field (controlId), so the label still points at it.

Monospace digits, italic help

<script lang="ts">	import { Field, Input } from 'omaris';</script>​<div class="flex w-72 max-w-full flex-col gap-4">	<Field label="Coupon" required error="Unknown code." controlId="coupon-code">		<Input required={false} value="SPRING" />	</Field>	<Field		label="Reading"		description="Monospace digits, italic help"		classes={{ label: 'uppercase tracking-wide', description: 'italic' }}	>		<Input value="42.0000" classes={{ control: 'font-mono tabular-nums' }} />	</Field></div>