SvField

The shared field chrome for every value-bearing editor in the kit - the label, hint, and error line that make any control behave consistently.

SvField renders an optional label (wired to your control via for / id), the control itself as children, and an optional hint or error line whose ids match aria-describedby conventions. Every editor in the kit (inputs, selects, SvFileUpload, and more) wraps its control box in it, so label / hint / error / RTL behave identically everywhere - and you can use it directly to give a custom control the same chrome.

Related: SvForm ยท Layout & composite overview

Installation

Add it with the CLI - this drops a ready-to-edit SvField starter into your app:

Prefer to see it first? npx @svgrid/ui try field opens it in a throwaway sandbox - no project needed.

Or install the package and import it directly. SvField ships free in @svgrid/grid (dependency-free):

import { SvField } from '@svgrid/grid'

Example

<script lang="ts">
  import { SvField } from '@svgrid/grid'
  const id = 'ticket-priority'
</script>

<SvField {id} label="Priority" hint="How urgent is this?" required>
  <select {id} class="my-control">
    <option>Low</option><option>High</option>
  </select>
</SvField>

Props

Prop Type Default Description
id string - Control id. The label's for, and the hint / error ids, derive from it.
label string - Visible label, rendered above the control.
hint string - Helper text under the control (shown when there is no error).
error string - Error message; when set it replaces the hint and gets role="alert".
required boolean false Adds a required marker to the label.
dir EditorDir (ltr | rtl | auto) - Text direction. rtl mirrors alignment; auto inherits the page.
block boolean false Stretch the field and its control to the container width.
loading boolean false Busy state; shows a small spinner beside the label.
children Snippet - The control to wrap (required).

When both error and hint are set, the error takes precedence and is the line announced to assistive tech.

Framed mode (shared control chrome)

Pass frame and SvField owns the bordered control box - the border, focus ring, invalid state, size (sm / md / lg), a shared clear button, adornments and floating label - so editors stop re-implementing them. The whole text-input family uses this; you only need it directly when building a custom framed control.

Prop Type Default Description
frame boolean false Own the bordered control box (opt-in).
invalid boolean false Error styling on the box + border.
size sm | md | lg md Control height / density.
disabled / readonly boolean false Dim / read-only box styling.
leading / trailing Snippet - Icon/button adornment at the start / end of the box.
prefix / suffix string - Plain-text affix at the start / end (units).
clearable + showClear + onclear - - Render the shared clear (x) button and handle the clear.
actions EditorAction[] - Compact in-field action buttons - the general form of clear/reveal (lookup, generate, copy). EditorAction is { label; onClick; icon?; disabled? }.
width number | string 220 Control width (block overrides to 100%).
labelMode static | floating static floating rests the label in the box and animates it up on focus/value.
filled boolean false Floating mode: whether the control holds a value (keeps the label up).

Examples

Wrap a custom control

Give any input the kit's label / hint / error treatment by matching the control's id to the field id:

<SvField id="color" label="Brand color" hint="Hex or named color">
  <input id="color" type="text" />
</SvField>

Drive the error from validation

Pass a reactive error string; clearing it swaps back to the hint automatically:

<SvField id="qty" label="Quantity" error={qtyError}>
  <input id="qty" type="number" bind:value={qty} />
</SvField>

Full-width fields

Set block so the field fills a form column rather than shrinking to the label width.

A native select that matches the kit

Give a plain <select> the same label, required marker, hint, and full-width behaviour every kit editor has by sharing one id, and drive error reactively:

<script lang="ts">
  import { SvField } from '@svgrid/grid'
  let role = $state('')
  const err = $derived(role ? undefined : 'Pick a role')
</script>

<SvField id="role" label="Role" hint="Sets the default permissions"
  error={err} required block>
  <select id="role" bind:value={role}>
    <option value="">Choose...</option>
    <option value="admin">Admin</option>
    <option value="member">Member</option>
  </select>
</SvField>

Tip: when both hint and error are set the error wins and gets role="alert", so clearing the error string swaps the hint back in automatically.

Accessibility

Wrapping a control you own

SvField is the label / hint / error chrome without an input of its own, so a native control or a third-party widget gets the same treatment as the built-in editors. Match id to the control's id and the label points at the right thing.

<script lang="ts">
  import { SvField } from '@svgrid/grid'

  let colour = $state('#2563eb')
</script>

<SvField id="brand" label="Brand colour" hint="Any CSS colour" required>
  <input id="brand" type="color" bind:value={colour} />
</SvField>

<SvField id="notes" label="Notes" error="Say something before saving">
  <textarea id="notes" rows="3"></textarea>
</SvField>

See also