KQ-1325 · SETTINGS/FORM

Settings Form

A settings form built from typed sections that knows what you changed: a changed field grows an edge bar on snap with a bloom of accent washing into its row, and a save bar slides up on snap counting the changes, its digit rolling as fields change and come back. Discard plays every change backwards — text un-types and re-types, a switch's knob slides home, a choice's indicator slides back, a select's label rolls back down, a range's thumb glides home — newest edit first; Save waits on a promise, then confirms field by field with a check drawn on flick while the count rolls down, and fields the save refuses shake and keep their message. Enter and Ctrl/⌘+S save, Escape takes a changed text field back, every field has its Revert, and each control is native or a real widget.

KQ-1325 · SETTINGS/FORM

Workspace settings

Fieldline Labs · changes apply to everyone in the workspace

Workspace

How Fieldline Labs appears to the team and on invoices.

Shown in the sidebar and on every invoice.

Changed from “Fieldline Labs”.

Old links keep working for 30 days after a change.

fieldline.app/

One line for the team directory.

Notifications

What reaches your inbox and your phone.

Email digest

A summary of what changed in your projects.

Changed from Weekly.
Mentions

Email me when someone mentions me.

Incident alerts

Text the on-call phone when a route fails.

Regional and security

Schedules and digests use this clock.

Session timeout

Sign out after this long without activity.

1 h

2unsaved changes

2 unsaved changes · newest: email digest

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/settings-form

Props

sections
SettingsSection[]
default defaultSettingsSections
The form: sections with a title, a line of help and fields — text (with prefix and validate), textarea, switch, choice, select or range — each with its own defaultValue.
value / defaultValue
SettingsValues
default —
The saved values, by field id: what the draft is compared against. Controlled or uncontrolled; fields left out use their own defaultValue (settingsValuesOf builds the full set).
defaultDraft
SettingsValues
default —
Edits to start from over the saved values — a draft restored from an earlier visit. They count as changes: the fields glow and the bar is up from the first render.
onValueChange
(values: SettingsValues) => void
default —
Fires when a save lands, with every saved value. Fields the save refused keep their old value.
onDraftChange
(draft: SettingsValues, dirty: string[]) => void
default —
Fires on every change to the draft — edits, reverts and each field a rewind brings back — with the ids that differ from what is saved.
onSave
(changes: SettingsChange[], draft: SettingsValues) => void | { errors?: Record<string, string> } | Promise<…>
default —
Save was pressed (or Ctrl/⌘+S, or Enter in a text field). A promise holds the bar in Saving; resolve with { errors } to refuse some fields with a message, reject to keep everything changed.
onDiscard
(changes: SettingsChange[]) => void
default —
Discard was pressed, with the changes being undone, in the order they will rewind.
glow
number
default 0.6
How far and how bright a changed field's edge glows into its row, 0 to 1. 0 keeps only the edge bar.
bar
"dock" | "float" | "inline"
default "dock"
Where the save bar lives: docked to the panel's bottom edge, a floating pill above it, or in the flow at the form's end.
rewind
"sequence" | "together" | "instant"
default "sequence"
How Discard undoes: each field plays its change backwards newest edit first, all fields at once, or every value swaps back at once with only the glow fading.
rewindDuration
number
default 520
The longest one field's rewind may take, in ms. Short text rewinds faster.
confirmStagger
number
default 110
Time between fields confirming after a save, in ms.
savedHold
number
default 1400
How long "All changes saved" stays before the bar leaves, in ms.
title
string
default "Settings"
The panel's heading; also its accessible name unless label is given. Focus lands here when the bar leaves with focus inside it.
description
string
default —
A line under the heading.
label
string
default —
The panel's accessible name. Defaults to the title.
saveLabel
string
default "Save"
The Save button's text.
discardLabel
string
default "Discard"
The Discard button's text.
status
"ready" | "loading" | "error"
default "ready"
Whether the saved values have arrived: a skeleton while loading, a message with Try again on error.
onRetry
() => void
default —
Try again was pressed while status is "error".
sound
boolean
default false
Clicks for Save, Discard and Revert, a softer falling click as each rewound field lands, and a pop for each field a save you started confirms.
disabled
boolean
default false
Read only: every control is disabled and no bar appears.
className
string
default —
Classes for the root. It is 560px tall and scrolls inside itself, the dock and float bars sticky to its bottom; pass a height class to change it.