Turn each piece on and off, and swap the control underneath.
Threshold
42
Alerts fire when a reading crosses this.
Control
Required
Hint
Help
Error
<WildFormField
label="Threshold"
help="Alerts fire when a reading crosses this."
>
<WildTextInput v-model="threshold" />
</WildFormField>
When to use
Use a form field around every input, select and toggle in a form, so each one gets a label and room for help and an error.
Use hint for a word or two on the label row, such as Optional.
Don’t use it
For a single checkbox. Use the Checkbox’s own label.
Anatomy
A label and optional hint, the control, then help text or an error.
Site name*
Bore 12 — north paddock
ThresholdOptional
42
Alerts fire when a reading crosses this.
<WildFormField label="Threshold" hint="Optional" help="Alerts fire when a reading crosses this.">
<WildTextInput v-model="threshold" />
</WildFormField>
The label is 12px and the help 11px, both smaller than the 14px value, so the data outranks its scaffolding.
States
The error takes the help text’s place, so a field with help keeps its height when validation fires.
Threshold
42
Alerts fire when a reading crosses this.
Threshold
420
Must be between 0 and 100.
A field with no help text grows by one line when an error appears.
Controls
Site name
Bore 12
Region
North paddock
SMS alertsImmediate
Input, select and toggle take the same label, hint, help and error, so a settings column that mixes all three reads as one.
Content
Name the setting in the label, as a noun: Threshold, Region, SMS alerts.
Say what the setting does in the help: “Alerts fire when a reading crosses this.”
Say how to fix it in the error: “Must be between 0 and 100.”
Props
Prop
Type
Default
Description
label
string
—
The field’s name. A placeholder isn’t a label.
hint
string
—
A short note right of the label.
help
string
—
Guidance under the control.
error
string
—
Replaces the help while it’s set.
required
boolean
false
A red asterisk after the label.
Tokens
Token
Value
Where it lands
--font-size-sm
12px
Label.
--font-size-xs
11px
Hint, help and error.
--font-weight-medium
475
Label.
--color-grey-900
#4F4D55
Label, hint and help ink.
--color-error
#E12121
Required asterisk and error text.
(no token)
4px
Gap between label, control and message.
Textarea
Takes longer text, growing with its content up to a limit and then scrolling.
Use a textarea for free text that runs past one line, such as notes.
Set maxLength when the text has a hard limit, so people see the count before they reach it.
Don’t use it
For a single line, such as a name. Use Text input.
Sizes
sm is 140px tall with 12px text; lg is 200px with 13px. Both resize vertically only.
sm · 140px
lg · 200px
States
rest
hover
focus
default
error
disabled
Error outranks focus, so a field that’s both keeps its red edge and gains the focus ring outside it. Both draw a 2px edge inside the 1px border, so the text never moves.
Accessibility
It’s a native textarea, so typing and selection work as usual. Give it a name with ariaLabel. Error sets aria-invalid, and the counter is announced politely as it changes.
Key
What it does
Tab
Moves focus into the textarea, and out again.
Props
Prop
Type
Default
Description
modelValue
string
—
The text.
size
'sm' | 'lg'
'sm'
140px or 200px tall.
maxLength
number
—
Adds a counter; it turns amber past 90%.
placeholder
string
—
A prompt shown while empty.
error
boolean
false
A 2px red edge; sets aria-invalid.
disabled
boolean
false
Greys the field and blocks typing.
ariaLabel
string
—
Accessible name.
Tokens
Token
Value
Where it lands
--radius-lg
8px
Corners, the same as every field.
--font-size-sm
12px
Text at sm.
--font-size-md
13px
Text at lg.
--global-neutral-grey-600
#DCDCDE
Border at rest, 1px.
--global-neutral-grey-800
#ADACB0
Border on hover.
--global-blue-1000
#1877F2
The 2px edge on focus, and the caret.
--global-red-800
#E12121
The 2px edge on error.
(no token)
0 0 0 3px, 12%
Halo on focus.
--global-neutral-grey-300
#F1F1F1
Ground when disabled.
--global-neutral-grey-1000
#4F4D55
Placeholder and counter.
--color-warning-active
#9D6508
Counter past 90%.
Select
Picks one option from a closed list, for choices too many for radios.
The placeholder is a prompt, never a label. Give the select a label with Form field.
States
rest
Bore 12
hover
Bore 12
focus
Bore 12
error
Bore 12
disabled
Bore 12
Focus and open share a 2px blue-1000 border and chevron. Open also flips the chevron.
Sizes
Two, matching the input: 36 and 44px.
Bore 12
sm · 36
Bore 12
lg · 44
Accessibility
Screen readers hear a combobox, collapsed or expanded. Focus stays on it while the arrows move through the list, and each option is announced as you reach it.
Key
What it does
Tab
Moves focus to the select.
↓ / ↑
Opens the list, then moves through it, skipping disabled options.
Enter / Space
Opens the list, or chooses the highlighted option.
Escape
Closes the list and keeps focus on the select.
Props
Prop
Type
Default
Description
modelValue
string | number | null
—
The chosen value.
options
{ value, label, disabled? }[]
—
The choices, in order.
placeholder
string
—
Shown until something is chosen.
size
'sm' | 'lg'
'sm'
36px or 44px tall.
disabled
boolean
false
Greys the select and blocks it.
error
boolean | string
false
Red border; a string also shows the message.
Tokens
Token
Value
Where it lands
--radius-lg
8px
The trigger’s corners, and the list’s.
--color-border-default
#E6E6E6
Border at rest.
--global-blue-1000
#1877F2
Border when focused or open.
--color-error
#E12121
Border on error.
--font-size-sm
12px
Value at sm.
--font-size-md
13px
Value at lg, and every option.
--color-grey-200
#F1F1F1
Highlighted and chosen options.
--global-blue-1100
#0C296A
The chosen option’s text, 12.07:1 on the grey row (blue-1000 would be 3.75:1).
A country selector and a number field, sharing one row and one frame style.
+1
202 555 0134
+64
21 555 0134
+966
55 555 0134
<WildPhoneInput v-model="phone" />
The selector shows the flag and code; the list adds the name. Its width is fixed, so the number field never shifts.
Country list
Nine countries in alphabetical order, with no search.
+64
412 345 678
+54 Argentina
+61 Australia
+880 Bangladesh
+52 Mexico
+264 Namibia
+64 New Zealand
+966 Saudi Arabia
+44 United Kingdom
+1 United States
The dialling code comes before the name. Names are spelled out, because NA and SA are ambiguous as codes.
States
Only the half you’re using changes.
rest
+64
21 555 0134
hover
+64
21 555 0134
focus
+64
21 555 0134
open
+64
21 555 0134
error
+64
21 555 0134
disabled
+64
21 555 0134
Errors frame the number only, because a country picked from a list can’t be wrong. An open list gives the selector the focus edge.
Accessibility
The selector is a combobox named Country calling code, and each country is announced as the arrows reach it. An error is announced as soon as it appears.
Key
What it does
Tab
Moves to the country selector, then the number.
↓ / ↑
Opens the list, then moves through the countries.
Enter / Space
Opens the list, or chooses the highlighted country.
A filled box looks like an empty one, so the digits show how far through the code you are. On error all six turn red, because the code is wrong as a whole.
Content
Write the error as what happened, in one short sentence: “That code has expired.”
Clear the error as soon as the code changes, because the field keeps it until you do.
Accessibility
Each box is its own input, named “Digit 1 of 6” and so on, inside one group. The error message is announced when it appears.
Key
What it does
A digit
Fills the box and moves to the next one.
Backspace
Clears the box. On an empty box, clears the one before and moves there.
← / →
Moves to the previous or next box.
Paste
Fills from the first box, then focuses the next empty one.
Tab
Moves through the boxes, then out.
Props
Prop
Type
Default
Description
v-model
string
—
The code, up to six digits.
error
string
—
Message under the boxes. Turns all six red.
disabled
boolean
false
Blocks all six boxes.
Tokens
Token
Value
Where it lands
--radius-lg
8px
Each box, the same as every field.
--global-blue-1000
#1877F2
The 2px edge of the box with the caret, and the caret itself. 4.23:1; the cyan was 2.53:1.
--global-neutral-grey-800
#ADACB0
Any box on hover.
--global-neutral-grey-600
#DCDCDE
Every box at rest, empty or filled, 1px.
--color-error
#E12121
The 2px edge of all six boxes, and the message.
--global-neutral-grey-300
#F1F1F1
The ground when disabled.
--font-size-2xl
20px
The digits.
--font-weight-medium
475
The digits.
Chip input
Turns typed entries, such as email addresses, into removable chips.
Live React portVue source: WildChipInput.vueStorybook story: Forms/Chip InputReact component: WChipInput
Try it
Remove a chip with its ×, or tab to the × and press Enter. Turn on Suggestions to see the match list.
JMJoel Mannsam@orchard.nznot-an-email
Size
Suggestions
Error
Disabled
<WildChipInput
v-model="recipients"
size="md"
placeholder="Add people by email"
/>
When to use
Use it to collect several email addresses in one field, such as when inviting people.
Check each address as its own chip, so one typo marks that address and not the whole line.
When a month is shorter than the chosen day, clamp moves the day to the month’s last day. hold keeps the stored day, shows the last day, and notes the held day beside the field.
Attach files to a form or record: reports, spreadsheets, photos.
Take several files at once, each with its own progress and outcome.
Use the compact variant when the upload is one field among several.
Don’t use it
For words someone could type, such as a note. Use Textarea.
For picking something already in the system. Use Search select.
Anatomy
The drop zone, then the file list: a summary header with Clear all, and one row per file.
Drop files here or browsePDFCSVJPGPNGup to 10 MB · 10 filesPDF, CSV, JPG and PNG, up to 10 MB, 10 files at most.Or focus here and paste a screenshot
6 files · 8.1 MB1 uploaded · 2 need attention
PDFnorth-pump-service-report.pdf1.2 MBUploaded
CSVtank-levels-2026.csv640 KBUploading · 62% · 4 s left
JPGlogger-photo-emu-park.jpg2.4 MBChecking the file
PDFreseller-agreement.pdf820 KBWaiting
PDFsite-survey-bore-12.pdf3.1 MBFailed: connection lost
ZIPfirmware-backup.zip14 MBPDF, CSV, JPG and PNG only
Each row shows the action its state needs: Cancel while it moves, Retry when it fails, Remove once it lands or is turned away.
Drag states
Drop files here or browsePDFCSVup to 10 MB · 10 filesPDF and CSV, up to 10 MB, 10 files at most.
rest
Release to add 3 filesPDFCSVup to 10 MB · 10 filesPDF and CSV, up to 10 MB, 10 files at most.
valid drag
PDF and CSV onlyPDFCSVup to 10 MB · 10 filesPDF and CSV, up to 10 MB, 10 files at most.
wrong kind of file
The zone judges the kind of file before the drop, in colour and words together. Size and count are checked once the files land.
Compact
One row in place of the full zone. It keeps the drag states, paste and the list.
Acknowledgement note
Replaced the pressure sensor at Bore 12. Readings back to normal.
Photos
Attach photos or browseJPGPNGHEICup to 10 MB · 10 filesJPG, PNG and HEIC, up to 10 MB, 10 files at most.
1 file · 2.1 MB1 uploaded
JPGbore-12-new-sensor.jpg2.1 MBUploaded
Content
Make the title a short instruction: “Attach photos”, “Drop files here”.
List formats in formats as people know them. Rejections are built from it: “PDF, CSV and JPG only”.
Write the field error as what’s missing: “Attach at least one photo of the installed logger.”
Accessibility
The zone is a button named by its label and title, described by its formats and any error, and it announces each drag message. Row actions name their file, such as “Retry site-survey-bore-12.pdf”.
Key
What it does
Tab
Moves from the zone to Clear all, then each row’s actions.
Enter / Space
On the zone, opens the file picker. On a row action, runs it.
Ctrl / ⌘ + V
On the zone, attaches a copied image.
Props
Prop
Type
Default
Description
items
DropItem[]
—
The files and their state, from queued to done or rejected.
accept
string
—
MIME types and extensions, as for a file input.
formats
string[]
—
Short names shown as tags beside the size limit.
maxSize
number
10 MB
Per file. Larger files are rejected with the reason.
maxFiles
number
10
Most files the list holds. Extras are rejected.
multiple
boolean
true
Allow more than one file per pick or drop.
variant
'default' | 'compact'
'default'
A full zone, or one row for a form.
disabled
boolean
false
Blocks picking, dropping and pasting.
title
string
'Drop files here'
The zone’s instruction, and part of its name.
label / hint / help / error
string
—
Field label, hint, help line and error message.
paste
boolean
true
Attach a copied image by pasting on the focused zone.
onAdd
(accepted, rejected) => void
—
Files that passed validation, and those that didn’t, with reasons.
onRetry / onCancel / onRemove
(id) => void
—
The row actions.
onClear
() => void
—
Clear all, shown once nothing is moving.
Tokens
Token
Value
Where it lands
--global-neutral-grey-600
#DCDCDE
Resting dashed border.
--global-neutral-grey-800
#ADACB0
Border on hover.
--global-blue-1000
#1877F2
Focus and valid-drag edge, badge, progress.
--global-blue-100
#EBFAFF
Valid drag ground.
--color-error
#E12121
Error and wrong-kind edge, badge.
--global-red-100
#FEEBEB
Wrong-kind ground, rejected row.
--radius-xl
12px
Zone and list card.
--radius-lg
8px
Thumbnails and type tiles.
Inline edit title
Lets a heading be renamed in place, without opening a form.
Live React portVue source: WildInlineEditTitle.vueStorybook story: Forms/InlineEditTitle
Try it
Click the name and type. Enter finishes, Escape puts the old name back.
A label above, an optional hint on the right, the options, then help or an error below.
Pressure unitShown on every chart
kPa
bar
psi
Changes how pressure readings are shown.
Layouts
Stack options that are sentences. Use a row only for three or four short words.
kPa
bar
psi
vertical
kPa
bar
psi
horizontal
Option cards
When each choice needs a line of explanation, make the option a card.
Pressure unit
kPaKilopascals
barBar, equal to 100 kPa
psiPounds per square inch
Selected adds a blue tint and ring. The edge stays 1px in every state, so choosing never shifts the layout.
States
kPa
bar
psi
rest
kPa
bar
psi
Choose a unit.
error
kPa
bar
psi
one option disabled
kPa
bar
psi
group disabled
Error turns every enabled ring red and leaves the labels dark. Write the message as what to do: “Choose a unit.”
Accessibility
The group is one tab stop, and a screen reader hears its label as focus enters. An error is announced when it appears. Give a group with no visible label an ariaLabel.
Key
What it does
Tab
Moves to the chosen option, or the first enabled one.
↓ / →
Chooses the next option, skipping disabled ones and wrapping.
↑ / ←
Chooses the previous option.
Home / End
Chooses the first or last option.
Space / Enter
Chooses the focused option.
Props
Prop
Type
Default
Description
value
string
—
The chosen option’s id.
defaultValue
string
—
Starting choice when value isn’t set.
onChange
(id: string) => void
—
Called with the newly chosen id.
options
{ id, label, sub?, disabled? }[]
—
The choices, in order.
label
string
—
The group’s visible name.
hint
string
—
Short context, right of the label.
help
string
—
Guidance under the options.
error
boolean | string
false
A string replaces the help as the message.
orientation
'vertical' | 'horizontal'
'vertical'
Stack or row.
variant
'plain' | 'card'
'plain'
Card adds an outline, a selected tint and padding.
size
'sm' | 'lg'
'sm'
Radio diameter: 18 or 24px.
disabled
boolean
false
Disables every option.
name
string
—
Posts the value with a form.
ariaLabel
string
—
Accessible name when there’s no visible label.
Tokens
Token
Value
Where it lands
--global-blue-1000
#1877F2
Chosen radio, unchosen hover, focus ring.
--global-blue-1100
#0C296A
Chosen hover, unchosen press.
--global-blue-1200
#081B45
Chosen press.
--global-neutral-grey-900
#7F7D83
Resting radio ring.
--global-neutral-grey-700
#C9C9CC
Disabled ring, card outline on hover.
--global-neutral-grey-500
#E6E6E6
Resting card outline.
--global-blue-300
#BDEDFF
Ring around a chosen card.
--global-blue-100
#EBFAFF
Ground of a chosen card.
--global-red-800
#E12121
Error ring and message.
--global-red-300
#FFC9C9
Card outline in the error state.
--global-neutral-grey-1300
#0A090B
Option labels.
--global-neutral-grey-1100
#2D2B32
Sub-lines.
--global-neutral-grey-1000
#4F4D55
Group label, hint and help.
--radius-lg
8px
Card corners.
Text input
The single-line field every form is built from, with its own label, message and counter, in four content shapes.
Type, tab and paste into it. Paste a full address into website and the https:// comes off.
Use a name your team will recognise.
Type
Size
Icon
Clear button
Counter
Error
Read-only
Disabled
<WildTextInput
v-model="siteName"
size="sm"
label="Site name"
help="Use a name your team will recognise."
clearable
>
<template #leading>
<MapPinIcon />
</template>
</WildTextInput>
Type “pu” and press Enter, then try “ohau”, the arrow keys and Escape.
16 on this account
Choose where this alarm watches.
v-model""@select—
Size
Min characters
Row icons
Sub-lines
Free text
Error
Disabled
<WildInputAutoComplete
v-model="query"
:options="sites"
label="Site or logger"
hint="16 on this account"
placeholder="Search sites and loggers"
help="Choose where this alarm watches."
size="sm"
:max-results="6"
clearable
@select="watch"
>
<template #leading>
<MagnifyingGlassIcon />
</template>
</WildInputAutoComplete>
When to use
Use it to pick one site, logger or person from a long list.
Turn on allow-custom when the answer may be outside the list.
The menu flips when it doesn’t fit and the other side has more room, and scrolls when neither side fits.
One choice
With one choice, the button does it straight away.
Opens a menu of types.
bore 12 · five alarm types
Adds it straight away.
rain gauge 4 · one alarm type
<!-- five types: a menu -->
<WildSelectButtons label="Add alarm" :options="boreTypes" @button-clicked="addAlarm" />
<!-- one type: no menu, no chevron -->
<WildSelectButtons label="Add rainfall alarm" :options="[rainfall]" @button-clicked="addAlarm" />
Name the choice on the button. The event is the same, so calling code doesn’t change.
States
While the menu is open, the button keeps its hover fill.
rest
hover
focus
disabled
High levelReading rises above a threshold
Low levelReading falls below a threshold
Rate of changeNeeds 5-minute readings
pointer on a choice
High levelReading rises above a threshold
Low levelReading falls below a threshold
Rate of changeNeeds 5-minute readings
keys on a disabled choice
A disabled choice stays on the key path, so its description can say why.
In context
Choose an alarm type and it joins the card’s list.
AlarmsBore 12 · Emu Park
High levelAbove 180 kPa · SMS to 2 peopleArmed
No dataNo reading for 2 hours · EmailArmed
Low batteryUnder 3.4 V · EmailPaused
Turn dropUp off in a card header, so the menu drops over the card’s list.
Content
Start with a verb and name the object: Add alarm.
With one choice, name it: Add rainfall alarm.
Keep descriptions to one line, or they’re cut off.
Accessibility
Key
What it does
Enter / Space
Opens the menu, or does the one choice. In the menu, chooses.
↓ / ↑
Opens the menu on the first or last choice. In the menu, moves, wrapping.
Home / End
Moves to the first or last choice.
A letter
Moves to the next choice that starts with it.
Escape
Closes the menu and returns to the button.
Tab
Closes the menu and moves on.
Props
Rows from options[].description down are refined additions.
Prop
Type
Default
Description
label
string
'Add new alarm'
Button text.
options
SelectOption[]
—
Choices, in order, each { Id, Name }.
@button-clicked
(option: SelectOption) => void
—
Fires with the choice.
align
'start' | 'end'
'end'
Button edge the menu aligns to.
dropUp
boolean
true
Opens above. Flips when it doesn’t fit.
autoSelectSingle
boolean
true
One option: choose it, no menu.
buttonClass
string
'btn-primary btn-medium'
Button variant and size classes.
triggerIcon
string | null
null
Icon name on the button.
triggerIconOpen
string | null
null
Icon while the menu is open.
triggerIconPosition
'left' | 'right'
'right'
Icon side of the label.
options[].description
string
—
One line under the label.
options[].icon
string
—
Icon name before the label.
options[].disabled
boolean
false
Dims the choice. Keys still reach it.
heading
string
—
Menu heading, and its accessible name.
chevron
boolean
true
Trailing chevron that turns over while open.
disabled
boolean
false
Disables the button.
Tokens
Token
Value
Where it lands
--color-primary-hover
#0ABEFF
Primary fill while the menu is open.
--global-blue-1000
#1877F2
Ring on a row the keys reach.
--global-neutral-grey-500
#E6E6E6
Menu outline and icon tile ring.
--global-neutral-grey-300
#F1F1F1
Highlighted row.
--global-neutral-grey-400
#ECECED
Pressed row.
--global-neutral-grey-1000
#4F4D55
Descriptions and the heading.
--shadow-dropdown
0 4px 12px rgba(0,0,0,.08), …
Menu elevation.
Date time picker
A date and a time chosen together, on the site’s clock, built for scheduling rather than for filtering.