MotionForm
Fifteen animated form interactions built on TuffEx form controls.
Usage
All Variants
validate only requests work: the caller writes back status and error, and changing validationKey replays the shake.
Loading demo...
Best Practices
- Keep values, validation messages, and business status in the caller; the component never decides success or clears an error on a timer.
- Treat
filesSelectedas a selection only: upload eachFilethrough your own service and drivestatusfrom the result. - Always pass a
labeland localizedlabels; OTP digit names are built fromlabeltoo. - Use
readonlyonly for text fields and OTP; usedisabledfor choices, files, the slider, and actions. - Set
nativeType="submit"only when an enclosing native form owns submission, and don't run the same work from both the click and the form's submit.
API Reference
Props
| Name | Type | Default | Description |
|---|---|---|---|
variant | MotionFormVariant | 'floating-label-input' | One of the fifteen effects in the variant table. |
modelValue | MotionFormValue | unset | Controlled value; its shape depends on the variant. |
label | string | '' | Visible label and accessible name; falls back to labels.field. |
placeholder | string | '' | Text and select placeholder; a resting floating label covers it. |
description | string | '' | Helper text in the message region; error and status take precedence. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Height, choice mark, and radius; action xs maps to Button sm. |
disabled | boolean | false | Blocks edits, selection, removal, password reveal, and action requests. |
readonly | boolean | false | Makes text, textarea, and OTP read-only; password reveal still works. |
required | boolean | false | Required marker and accessible state; native text fields also get required. |
status | 'default' | 'loading' | 'success' | 'error' | 'default' | Caller-driven status; loading blocks action requests. |
error | string | '' | When non-empty, sets the error state and shows this message. |
validationKey | string | number | unset | Replays the current error when it changes. |
labels | Partial<MotionFormLabels> | unset | Localizes static text, digit names, and removal labels. |
options | MotionFormOption[] | [] | Choices for radio, dropdown, and chips. |
inputType | 'text' | 'email' | 'number' | 'date' | 'text' | Text control type; the password variant switches text/password itself. |
autocomplete | string | unset | Native autocomplete; the first OTP box always uses one-time-code. |
passwordVisible | boolean | unset | Controlled reveal state, paired with update:passwordVisible. |
rows | number | 2 | Minimum textarea rows. |
maxRows | number | 8 | Maximum auto-grow rows before scrolling; never below rows. |
maxLength | number | unset | Length limit for text and textarea; OTP is fixed at 4 digits. |
accept | string | '*/*' | File type filter for picking and dropping. |
multiple | boolean | true | Multiple files; when false, a new file replaces the old one. |
maxFiles | number | 10 | Maximum number of files. |
min | number | 0 | Slider minimum. |
max | number | 100 | Slider maximum. |
step | number | 1 | Slider step. |
formatValue | (value: number) => string | unset | Formats the slider value and tooltip. |
nativeType | 'button' | 'submit' | 'button' | Native type of the submit button. |
motion | boolean | true | Enables motion, still gated by visibility, KeepAlive, and reduced motion. |
Events
| Event | Payload | Meaning |
|---|---|---|
update:modelValue | MotionFormValue | Fires on a user edit or selection. |
change | MotionFormValue | Fires together with update:modelValue. |
update:passwordVisible | boolean | Fires when password reveal toggles. |
focus, blur | FocusEvent | Fire when focus enters or leaves the component, not on internal moves. |
search | string | Fires when the search-expand text changes; sends no request. |
validate | MotionFormValue | Asks the caller to validate the current value. |
submit | [value: MotionFormValue | undefined, event: MouseEvent] | Asks the caller to do the work; doesn't change status. |
otpComplete | string | Fires when all four boxes hold digits; can fire again after an edit. |
filesSelected | FileUploaderFile[] | Newly accepted files only; neither the full list nor an upload completion. |
fileRemove | { id: string, value: FileUploaderFile[] } | Fires on removal with the file ID and the new list. |
Slots
| Slot | Scope | Use |
|---|---|---|
label | none | Visible label, linked to the control through a stable ID. |
prefix, suffix | none | Input affixes; suffix replaces the password reveal button. |
option | { option, selected } | Radio and dropdown option content. |
chip | { option } | Chip label; the remove button stays. |
file | { file, remove: () => void } | File row content; the remove button stays. |
submit | { status: MotionFormStatus, label: string } | Submit button content, beside the state glyph. |
status | { status, error, value } | Content of the live message region. |
Exposed Methods
| Method | Behavior |
|---|---|
focus() | Focuses the first available input, textarea, or action button. |
blur() | Blurs the focused descendant. |
Types
import type { FileUploaderFile } from '@talex-touch/tuffex/file-uploader'
import type { MotionFormProps, MotionFormVariant } from '@talex-touch/tuffex/motion-form'
type MotionFormValue = string | number | boolean | (string | number)[] | FileUploaderFile[]
type MotionFormOption = TxSelectOption // { value, label, disabled?, icon?, description? }
// FileUploaderFile: { id, name, size, type, file: File }
// MOTION_FORM_VARIANTS exports the full readonly variant tuple.
MotionFormVariant
| Original ID | variant | Model | Effect |
|---|---|---|---|
frm1 | floating-label-input | string or number | The label floats up and shrinks on focus or with a value. |
frm2 | input-focus-glow | string or number | A halo spreads on focus and retracts on blur. |
frm3 | password-toggle | string | The reveal button toggles plain text and spins the eye; the value is untouched. |
frm4 | search-expand | string | Widens within the available space on focus; the icon shifts. |
frm5 | checkbox-draw | boolean | Checking draws the tick and pops the box. |
frm6 | radio-scale | string or number | Single choice; the inner dot springs in. |
frm7 | error-shake | string or number | Shakes when error, the error status, or validationKey changes. |
frm8 | success-check | string or number | Requests validation; success springs in a drawn check. |
frm9 | select-dropdown | string or number | Select opens with origin-aware scale, offset, and fade. |
frm10 | multi-select-chips | (string | number)[] | Chips spring in and out; remove buttons update the array. |
frm11 | textarea-auto-grow | string | Grows with its scroll height, springy and capped. |
frm12 | otp-input | string | Four digit boxes auto-advance and distribute pasted text. |
frm13 | file-upload-dropzone | FileUploaderFile[] | Pick or drop files; dragging pulses the ring and lifts the arrow. |
frm14 | range-slider | number | Slider handles pointer and keyboard, with a springy thumb and value tooltip. |
frm15 | form-submit-button | optional MotionFormValue | Morphs text, spinner, and check from the caller's status. |
MotionFormLabels
Defaults are exported as MOTION_FORM_DEFAULT_LABELS; labels overrides any subset.
| Key | Default/type |
|---|---|
field | 'Field' |
showPassword, hidePassword, capsLock | 'Show password', 'Hide password', 'CapsLock is on' |
validate, validating, verified, validationError | 'Validate', 'Validating…', 'Verified', 'Validation failed' |
submit, submitting, submitted, submitError | 'Submit', 'Submitting…', 'Submitted', 'Submission failed' |
chooseFiles, dropFiles, fileHint | 'Choose files', 'Drop files here', 'or click to browse' |
searchOptions, noOptions | 'Search options', 'No options' |
otpDigit | (index: number) => string; one-based default Digit N of 4 |
removeOption | (label: string) => string; default Remove <label> |
removeFile | (name: string) => string; default Remove <name> |
CSS Variables
| Variable | md default | Role |
|---|---|---|
--tx-mf-height | 36px | Input and action height; sizes set 26/30/36/42px. |
--tx-mf-choice | 22px | Checkbox and radio mark size; sizes set 16/18/22/24px. |
--tx-mf-radius | 12px | Field radius; sizes set 8/10/12/12px. |
Colors come from --tx-color-*, --tx-text-color-*, --tx-bg-color, and --tx-border-color-*; motion variables are generated internally and aren't public API.
Overview
- Input, Select, Checkbox, Radio, Textarea, FileUploader, and Slider own editing, options, drag and drop, and keyboard semantics; this component adds motion and controlled events.
- Labels sit beside their controls, and
useIdlinks labels, helper text, and OTP boxes. The password button is a native button witharia-pressed. - Status and errors live in a
role="status" aria-live="polite"region; replaying motion never resets focus. - OTP accepts paste, autofill, Left/Right, Home/End, Backspace, and Delete; a new external value replaces all four boxes.
- The chips variant adds one option at a time and never adds a selected option twice.
- Motion and listeners pause when hidden or KeepAlive-inactive; reduced motion turns off decorative motion only, never input handling or measurement.
Technologies
- Text transitions use
TxTextMorphand curves come from the shared liquid spring resolver; upstream's timed error clearing and fake submit success became caller-ownederrorandstatus. - Upstream:
src/components/forms/AnimatedFormElement.tsxat Amicro commit 43c29ce, MIT, Copyright (c) 2026 SYED SUBHAN UDDIN. - Source:
packages/tuffex/packages/components/src/motion-form/.
查看源码
packages/tuffex/packages/components/src/motion-form/index.ts