Integrations
elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDeviceList
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMediaStream
- useMemory
- useNetwork
- useNotification
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
- useVibrate
- useVirtualKeyboard
- useWakeLock
- useWebSocket
utilities
state
- useBoolean
- useControllableState
- useCookie
- useCookies
- useCounter
- useCycleList
- useDefault
- useDisclosure
- useField
- useForm
- useHash
- useList
- useLocalStorage
- useMap
- useMask
- useMergedRef
- useObject
- useOffsetPagination
- useQueue
- useRafState
- useRefState
- useSessionStorage
- useSet
- useStateHistory
- useStep
- useStorage
- useToggle
- useUrlSearchParam
- useUrlSearchParams
- useValidatedState
- useWizard
user
sensors
- useDeviceMotion
- useDeviceOrientation
- useHotkeys
- useIdle
- useInfiniteScroll
- useIntersectionObserver
- useKeyboard
- useKeyPress
- useKeysPressed
- useMouse
- useMutationObserver
- useOrientation
- usePageLeave
- useParallax
- usePerformanceObserver
- useResizeObserver
- useScroll
- useScrollIntoView
- useScrollTo
- useSwipe
- useTextSelection
- useVisibility
- useWindowEvent
- useWindowFocus
- useWindowScroll
- useWindowSize
Account settings
Update your public profile and preferences.
import { useForm } from '@siberiacancode/reactuse';
import { CheckIcon, ChevronDownIcon } from 'lucide-react';
const LANGUAGES = [
{ value: 'en', label: 'English' },
{ value: 'ru', label: 'Russian' },
{ value: 'de', label: 'German' }
];
const EMAIL_PATTERN = /^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/;
const Demo = () => {
const form = useForm({
initialValues: {
name: 'siberiacancode',
email: 'hello@reactuse.org',
bio: 'Building open-source React hooks',
language: 'en',
notifications: true,
public: false
},
validateOnBlur: true
});
const values = form.watch();
const onSubmit = form.handleSubmit((values) => {
console.log('submit', values);
});
return (
<section className='flex w-full max-w-md flex-col gap-1 p-4'>
<div className='mb-3 flex flex-col gap-1'>
<h2 className='text-foreground text-sm font-semibold'>Account settings</h2>
<p className='text-muted-foreground text-xs'>Update your public profile and preferences.</p>
</div>
<form className='flex flex-col gap-4' onSubmit={onSubmit}>
<div className='flex flex-col gap-1.5'>
<label className='text-foreground text-xs font-medium' htmlFor='name'>
Display name
</label>
<input
className='border-border bg-card text-foreground rounded-md border px-3 py-2 text-sm outline-none'
id='name'
placeholder='Your name'
{...form.register('name', {
required: 'Name is required',
minLength: { value: 2, message: 'At least 2 characters' }
})}
/>
{form.errors.name && <span className='text-destructive text-xs'>{form.errors.name}</span>}
</div>
<div className='flex flex-col gap-1.5'>
<label className='text-foreground text-xs font-medium' htmlFor='email'>
Email
</label>
<input
className='border-border bg-card text-foreground rounded-md border px-3 py-2 text-sm outline-none'
id='email'
placeholder='you@example.com'
type='email'
{...form.register('email', {
required: 'Email is required',
pattern: { value: EMAIL_PATTERN, message: 'Invalid email format' }
})}
/>
{form.errors.email && (
<span className='text-destructive text-xs'>{form.errors.email}</span>
)}
</div>
<div className='flex flex-col gap-1.5'>
<label className='text-foreground text-xs font-medium' htmlFor='bio'>
Bio
</label>
<textarea
className='border-border bg-card text-foreground min-h-[72px] resize-none rounded-md border px-3 py-2 text-sm outline-none'
id='bio'
placeholder='Tell something about yourself...'
{...form.register('bio')}
/>
</div>
<div className='border-border flex flex-col gap-3 border-t pt-4'>
<label className='flex cursor-pointer items-start justify-between gap-3'>
<div className='flex flex-col gap-0.5'>
<span className='text-foreground text-xs font-medium'>Email notifications</span>
<span className='text-muted-foreground text-[11px]'>
Receive product updates and release notes
</span>
</div>
<input role='switch' type='checkbox' {...form.register('notifications')} />
</label>
<div className='flex items-center justify-between gap-3'>
<div className='flex flex-col gap-0.5'>
<label className='text-foreground text-xs font-medium' htmlFor='language'>
Language
</label>
<span className='text-muted-foreground text-[11px]'>
Choose your preferred language
</span>
</div>
<div className='relative'>
<select
className='border-border bg-card text-foreground w-32 appearance-none rounded-md border py-1.5 pr-7 pl-3 text-xs outline-none'
id='language'
{...form.register('language')}
>
{LANGUAGES.map((language) => (
<option key={language.value} value={language.value}>
{language.label}
</option>
))}
</select>
<ChevronDownIcon className='text-muted-foreground pointer-events-none absolute top-1/2 right-2 size-3.5 -translate-y-1/2' />
</div>
</div>
</div>
<label className='flex cursor-pointer items-start gap-3'>
<span className='mt-0.5 flex shrink-0 items-center'>
<input className='peer sr-only' type='checkbox' {...form.register('public')} />
<span className='border-border peer-checked:border-foreground peer-checked:bg-foreground flex size-4 items-center justify-center rounded-[5px] border transition-colors'>
{values.public && <CheckIcon className='text-background size-3' strokeWidth={3.5} />}
</span>
</span>
<div className='flex flex-col gap-0.5'>
<span className='text-foreground text-xs font-medium'>Make profile public</span>
<span className='text-muted-foreground text-[11px]'>
Anyone on the internet can see your profile
</span>
</div>
</label>
<div className='flex justify-end'>
<button disabled={form.submitting} type='submit'>
{form.submitting ? 'Saving...' : 'Save changes'}
</button>
</div>
</form>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const form = useForm({ initialValues: { email: '' } });Type Declarations
import type { BaseSyntheticEvent, ChangeEventHandler, FocusEventHandler } from 'react';
type UseFormElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
export type UseFormErrors<Values> = Partial<Record<keyof Values, string>>;
export interface UseFormResolverResult<Values> {
/** The errors map keyed by field name */
errors: UseFormErrors<Values>;
/** The parsed values, empty object when validation fails */
values: Values;
}
export interface UseFormTriggerOptions {
/** Focus the first invalid field */
shouldFocus?: boolean;
}
export type UseFormResolver<Values> = (
values: Values
) => Promise<UseFormResolverResult<Values>> | UseFormResolverResult<Values>;
export interface UseFormRegisterParams<Values = any> {
/** The max value validation */
max?: {
value: number;
message: string;
};
/** The max length validation */
maxLength?: {
value: number;
message: string;
};
/** The min value validation */
min?: {
value: number;
message: string;
};
/** The min length validation */
minLength?: {
value: number;
message: string;
};
/** The blur event handler */
onBlur?: FocusEventHandler<UseFormElement>;
/** The change event handler */
onChange?: ChangeEventHandler<UseFormElement>;
/** The pattern validation */
pattern?: {
value: RegExp;
message: string;
};
/** The required validation */
required?: string;
/** The custom validation */
validate?: (value: any, values: Values) => string | true | Promise<string | true>;
}
export interface UseFormOptions<Values> {
/** The field to focus on mount */
autoFocus?: keyof Values;
/** The initial values */
initialValues: Values;
/** The schema resolver, takes precedence over register params */
resolver?: UseFormResolver<Values>;
/** The validate on blur */
validateOnBlur?: boolean;
/** The validate on change */
validateOnChange?: boolean;
/** The validate on mount */
validateOnMount?: boolean;
}
export interface UseFormReturn<Values extends Record<string, any>> {
/** The dirty state per field */
dirty: Partial<Record<keyof Values, boolean>>;
/** The errors state per field */
errors: UseFormErrors<Values>;
/** The submitting state */
submitting: boolean;
/** The touched state per field */
touched: Partial<Record<keyof Values, boolean>>;
/** The clear errors function */
clearErrors: (name?: keyof Values) => void;
/** The focus function */
focus: (name: keyof Values) => void;
/** The get value function */
getValue: <Name extends keyof Values>(name: Name) => Values[Name];
/** The get values function */
getValues: () => Values;
/** The submit handler factory */
handleSubmit: (
onValid: (values: Values, event?: BaseSyntheticEvent) => any,
onInvalid?: (errors: UseFormErrors<Values>, event?: BaseSyntheticEvent) => any
) => (event?: BaseSyntheticEvent) => Promise<void>;
/** The register function */
register: (
name: keyof Values,
params?: UseFormRegisterParams<Values>
) => {
name: string;
onBlur: FocusEventHandler<UseFormElement>;
onChange: ChangeEventHandler<UseFormElement>;
ref: (node: UseFormElement | null | undefined) => void;
};
/** The reset function */
reset: (values?: Partial<Values>) => void;
/** The set error function */
setError: (name: keyof Values, error: string) => void;
/** The set value function */
setValue: <Name extends keyof Values>(name: Name, value: Values[Name]) => void;
/** The validate function */
trigger: (
name?: (keyof Values)[] | keyof Values,
options?: UseFormTriggerOptions
) => Promise<boolean>;
/** The watch function */
watch: () => Values;
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| options.initialValues | Values | - | Initial values |
| options.resolver | UseFormResolver<Values> | - | Schema resolver |
| options.autoFocus | keyof Values | - | Field to focus on mount |
| options.validateOnChange | boolean | false | Validate on change |
| options.validateOnBlur | boolean | false | Validate on blur |
| options.validateOnMount | boolean | false | Validate on mount |
Returns
UseFormReturn<Values>Contributors
ddebabin
Last updated on