Component & design-token showcase

Forms

Every field below runs through a real SvelteKit remote form (no database — it just returns a success message). This is the pattern every app form should follow, not a hand-rolled input + onsubmit.

Sizes

Omit size for the default 35px height. size='sm' is the one shorter footprint (28px) — for filter bars, dense panels, inline row editing. Same two-tier scale as Button.

Code
<Input placeholder="Default (35px)" />
<Input placeholder="Small (28px)" size="sm" />
A complete form

<Form> + field components + <Button form>, wired to src/lib/remote/demo.remote.ts. The success message is toasted automatically — no onSuccess wiring needed just to surface it. Field schemas come from zeyo-kit/utils/form (formText, formEmail, nullable(...), …), never raw zod.

Code
<Form form={demoContactForm} schema={DemoContactSchema}>
  <TextField name="name" form={demoContactForm}>Name</TextField>
  <EmailField name="email" form={demoContactForm}>Email</EmailField>
  <SelectField
    name="topic"
    form={demoContactForm}
    getKey={(opt) => opt.value}
    getLabel={(opt) => opt.label}
    getValue={(opt) => opt.value}
    items={topicOptions}
    label="Topic"
    placeholder="Topic"
  />
  <NumberField name="seats" form={demoContactForm} optional>Seats (optional)</NumberField>
  <MessageField name="message" form={demoContactForm} optional>Message (optional)</MessageField>
  <SwitchField name="urgent" form={demoContactForm} optional variant="onoff">Urgent</SwitchField>
  <CheckboxField name="subscribe" form={demoContactForm} optional>Subscribe to updates</CheckboxField>
  <Button form={demoContactForm}>Send</Button>
</Form>
RadioField

zeyo-ui/form/fields: one radio option. Options that share a name form a group, and group holds the selected value, so the options can sit anywhere (a table row, beside other content), not only inside one wrapper. Styled and spaced like CheckboxField.

Rows with the same value count as one lead.

Selected: growth

Code
<RadioField name="plan" value="starter" bind:group={plan}>Starter</RadioField>
<RadioField name="plan" value="growth" bind:group={plan}>Growth</RadioField>
<RadioField name="plan" value="scale" disabled bind:group={plan}>Scale</RadioField>
InfoTip

zeyo-ui/popover — a small info icon whose tooltip shows on hover or keyboard focus. Use it for a short explanation next to a label or column header. align='right' makes the tooltip open leftwards, for one placed in the last column.

Match leads by

Code
<InfoTip label="About matching leads">
  Rows with the same value count as the same lead.
</InfoTip>
Combobox

zeyo-ui/form — type to filter (fuzzy match). See the dedicated Combobox page for multi-select, header/footer snippets, and form-bound usage; SelectField's items/getKey/getLabel/getValue array (also on that page) is the non-searchable alternative.

Code
<Combobox name="priorityDemo" placeholder="Priority" bind:value={priority}>
  {#each priorityOptions as opt (opt.value)}
    <Option label={opt.label} value={opt.value}>{opt.label}</Option>
  {/each}
</Combobox>
Input

The standalone, non-form counterpart to TextField — same .form-input styling, plain bindable value. SearchBar is just this with a Search icon and type='search' baked in. Reach for this for any local-state input a remote form doesn't own (filters, modal-local fields, dynamically-named fields a static Field name can't express).

Code
<Input bind:value placeholder="Plain text" />
<Input bind:value icon={Mail} placeholder="jane@company.com" type="email" />
FileField

Not wired to a form — reads the file for client-side use (preview, direct upload to R2, …) instead of submitting through FormData.

Attachment
No file chosen
Attachment (dropzone)
Drag & drop or click to upload No file chosen
Code
<FileField onSelect={(files) => console.log(files)} variant="button" />
<FileField onSelect={(files) => console.log(files)} variant="dropzone" />