Forms in Svelte, inspired by Formik.
<script>
import { Sveltik, Form, Field, ErrorMessage } from 'sveltik'
let initialValues = {
email: '',
password: '',
}
let validate = values => {
const errors = {}
if (!values.email) {
errors.email = 'Required'
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
errors.email = 'Invalid email address'
}
return errors
}
let onSubmit = (values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
setSubmitting(false)
}, 400)
}
</script>
<Sveltik {initialValues} {validate} {onSubmit} let:isSubmitting>
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" as="div" />
<Field type="password" name="password" />
<ErrorMessage name="password" as="div" />
<button type="submit" disabled={isSubmitting}>Submit</button>
</Form>
</Sveltik>
<Sveltik /><Sveltik /> is a component for rendering forms. It is largely a port of
Formik to Svelte and broadly
follows the same API. It uses a let:props pattern which is generally similar to
the render prop pattern in React.
<script>
import { Sveltik } from 'sveltik'
</script>
<div>
<h1>My Form</h1>
<Sveltik
initialValues={{ name: 'jared' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
actions.setSubmitting(false)
}, 1000)
}}
let:props
>
<form on:submit|preventDefault={props.handleSubmit}>
<input
type="text"
on:input={props.handleInput}
on:blur={props.handleBlur}
value={props.values.name}
name="name"
/>
{#if props.errors.name}
<div id="feedback">{props.errors.name}</div>
{/if}
<button type="submit">Submit</button>
</form>
</Sveltik>
</div>
enableReinitialize?: booleaninitialErrors?: SveltikErrors<Values>initialStatus?: anyinitialTouched?: SveltikTouched<Values>initialValues: ValuesinitialWarnings?: SveltikWarnings<Values>onReset?: (values: Values, sveltikBag: SveltikBag) => voidonSubmit: (values: Values, sveltikBag: SveltikBag) => void | Promise<any>validate?: (values: Values, sveltikBag: SveltikBag) => SveltikErrors<Values>validateOnBlur?: booleanvalidateOnChange?: booleanvalidateOnMount?: booleanlet:props: SveltikPropslet:isDirty: booleanlet:errors: { [field: string]: string }let:handleBlur: (e: HTMLBlurEvent) => voidlet:handleInput: (e: HTMLInputEvent) => voidlet:handleReset: () => voidlet:handleSubmit: (e: HTMLFormEvent) => voidlet:isSubmitting: booleanlet:isValid: booleanlet:isValidating: booleanlet:resetForm: (nextInitialState?: SveltikState<Values>) => voidlet:scrollFirstErrorIntoView: () => voidlet:setErrors: (fields: { [field: string]: string }) => voidlet:setFieldError: (field: string, errorMsg: string) => voidlet:setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => voidlet:setFieldValue: (field: string, value: any, shouldValidate?: boolean) => voidlet:setFieldWarning: (field: string, warning: string) => voidlet:setStatus: (status?: any) => voidlet:setSubmitting: (isSubmitting: boolean) => voidlet:setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => voidlet:setValues: (fields: { [field: string]: any }, shouldValidate?: boolean) => voidlet:setWarnings: (fields: { [field: string]: string }) => voidlet:status: anylet:submitAttemptCount: numberlet:submitFailure: () => voidlet:submitFailureCount: numberlet:submitForm: () => Promiselet:submitSuccess: () => voidlet:submitSuccessCount: numberlet:touched: { [field: string]: boolean }let:values: { [field: string]: any }let:validateForm: (values?: any) => voidlet:validateField: (field: string) => voidlet:warnings: { [field: string]: string }enableReinitialize?: booleanDefault is false. Control whether Sveltik should reset the form if initialValues changes (using deep equality).
initialErrors?: SveltikErrors<Values>Initial field errors of the form, Sveltik will make these values available to render methods component as errors.
initialStatus?: anyAn arbitrary value for the initial status of the form. If the form is reset, this value will be restored.
initialTouched?: SveltikTouched<Values>Initial visitied fields of the form, Sveltik will make these values available to render methods component as touched.
initialValues: ValuesInitial field values of the form, Sveltik will make these values available to render methods component as values.
Even if your form is empty by default, you must initialize all fields with initial values.
onReset?: (values: Values, sveltikBag: SveltikBag) => voidYour optional form reset handler. It is passed your forms values and the "SveltikBag".
onSubmit: (values: Values, sveltikBag: SveltikBag) => void | Promise<any>Your form submission handler. It is passed your forms values and the "SveltikBag", which includes an object containing a subset of the injected props and methods (i.e. all the methods with names that start with set<Thing> + resetForm) and any props that were passed to the wrapped component.
If onSubmit returns a promise, rejection automatically calls submitFailure and resolution automatically calls submitSuccess.
validate?: (values: Values) => SveltikErrors<Values>Validate the form's values with function. Synchronous and return an errors object.
validateOnBlur?: booleanDefault is true. Use this option to run validations on blur events. More specifically, when either handleBlur, setFieldTouched, or setTouched are called.
validateOnChange?: booleanDefault is true. Use this option to tell Sveltik to run validations on change events and change-related methods. More specifically, when either handleInput, setFieldValue, or setValues are called.
validateOnMount?: booleanDefault is false. Use this option to tell Sveltik to run validations when the <Sveltik /> component mounts and/or initialValues change.
All of these props are exposed individually as well as a master let:props prop which is an object
of all available props.
let:isDirty: booleanReturns true if values are not deeply equal from initial values, false otherwise. dirty is a readonly computed property and should not be mutated directly.
let:errors: { [field: string]: string }Form validation errors. Should match the shape of your form's values defined in initialValues.
let:handleBlur: (e: HTMLBlurEvent) => voidonBlur event handler. Useful for when you need to track whether an input has been touched or not. This should be passed to
<input on:blur={handleBlur} ... />
let:handleInput: (e: HTMLInputEvent) => voidGeneral input change event handler. This will update the values[key] where key is the event-emitting input's name attribute. If the name attribute is not present, handleInput will look for an input's id attribute. Note: "input" here means all HTML inputs.
let:handleReset: () => voidReset handler. Will reset the form to its initial state. This should be passed to <button on:click={handleReset}>...</button>
let:handleSubmit: (e: HTMLFormEvent) => voidSubmit handler. This should be passed to <form on:submit|preventDefault={props.handleSubmit}>...</form>.
let:isSubmitting: booleanSubmitting state of the form. Returns true if submission is in progress and false otherwise.
let:isValid: booleanReturns true if there are no errors (i.e. the errors object is empty) and false otherwise.
let:isValidating: booleanReturns true if Sveltik is running validation during submission, or by calling validateForm directly false otherwise.
let:resetForm: (nextInitialState?: SveltikState<Values>) => voidImperatively reset the form. If nextInitialState is specified, Sveltik will set this state as the new "initial state" and use the related values of nextInitialState to update the form's initialValues as well as initialTouched, initialStatus, initialErrors. This is useful for altering the initial state (i.e. "base") of the form after changes have been made. If nextInitialState is not defined, then Sveltik will reset state to the original initial state.
let:scrollFirstErrorIntoView: () => voidScroll the first <ScrollMarker /> with an error into view. First is calculated by the vertical distance from the top of the document.
let:setErrors: (fields: { [field: string]: string }) => voidSet errors imperatively.
let:setFieldError: (field: string, errorMsg: string) => voidSet the error message of a field imperatively. field should match the key of errors you wish to update. Useful for creating custom input error handlers.
let:setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => voidSet the touched state of a field imperatively. field should match the key of touched you wish to update. Useful for creating custom input blur handlers. Calling this method will trigger validation to run if validateOnBlur is set to true (which it is by default). isTouched defaults to true if not specified. You can also explicitly prevent/skip validation by passing a third argument as false.
let:setFieldValue: (field: string, value: any, shouldValidate?: boolean) => voidSet the value of a field imperatively. field should match the key of values you wish to update. Useful for creating custom input change handlers. Calling this will trigger validation to run if validateOnChange is set to true (which it is by default). You can also explicitly prevent/skip validation by passing a third argument as false.
let:setFieldWarning: (field: string, warning: string) => voidSet the warning of a field imperatively. field should match the key of warnings you wish to update.
let:setStatus: (status?: any) => voidSet a top-level status to anything you want imperatively. Useful for controlling arbitrary top-level state related to your form. For example, you can use it to pass API responses back into your component in handleSubmit.
let:setSubmitting: (isSubmitting: boolean) => voidSet isSubmitting imperatively. You would call it with setSubmitting(false) in your onSubmit handler to finish the cycle.
let:setTouched: (fields: { [field: string]: boolean }, shouldValidate?: boolean) => voidSet touched imperatively. Calling this will trigger validation to run if validateOnBlur is set to true (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as false.
let:setValues: (fields: { [field: string]: any }, shouldValidate?: boolean) => voidSet values imperatively. Calling this will trigger validation to run if validateOnChange is set to true (which it is by default). You can also explicitly prevent/skip validation by passing a second argument as false.
let:setWarnings: (fields: { [field: string]: string }) => voidSet warnings imperatively.
let:status: anyA top-level status object that you can use to represent form state that can't otherwise be expressed/stored with other methods. This is useful for capturing and passing through API responses to your inner component. status should only be modified by calling setStatus.
let:submitAttemptCount: numberNumber of times user tried to submit the form. Increases when handleSubmit is called, resets after calling handleReset.
let:submitFailure: () => voidIncrement submitFailureCount by 1 and calls setSubmitting(false).
let:submitFailureCount: numberNumber of failed form submissions. Increases when submitFailure is called, resets after calling handleReset.
let:submitForm: () => PromiseTrigger a form submission. The promise will be rejected if form is invalid.
let:submitSuccess: () => voidIncrement submitSuccessCount by 1 and calls setSubmitting(false).
let:submitSuccessCount: numberNumber of successful form submissions. Increases when submitSuccess is called, resets after calling handleReset.
let:touched: { [field: string]: boolean }Touched fields. Each key corresponds to a field that has been touched/visited.
let:values: { [field: string]: any }Your form's values.
let:validateForm: (values?: any) => voidImperatively call validate. You can optionally pass values to validate against and this modify Sveltik state accordingly, otherwise this will use the current values of the form.
let:validateField: (field: string) => voidImperatively call field's validate function if specified for given field. Sveltik will use the current field value.
let:warnings: { [field: string]: string }Form warnings. Should match the shape of your form's values defined in initialValues.
warnings, setWarnings, setFieldWarningsubmitSuccess and submitFailure helperssubmitAttemptCount, submitFailureCount and submitSuccessCount instead of only submitCountonSubmit returns a promise, it's rejection calls submitFailure and it's resolution calls submitSuccessvalidateSchema<Field /><Field /> will automagically hook up inputs to Sveltik. It uses the name attribute to match up with Sveltik state.
With no options passed, <Field /> will default to an HTML <input /> element.
MyInput.svelte
<script>
export let field
export let props
</script>
<input {...field} {...props} on:input={field.handleInput} on:blur={field.handleBlur} />
App.svelte
<script>
import { Sveltik, Form, Field } from 'sveltik'
import MyInput from './MyInput.svelte'
</script>
<div>
<h1>My Form</h1>
<Sveltik
initialValues={{ email: '', color: 'red', firstName: '', lastName: '' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
actions.setSubmitting(false)
}, 1000)
}}
>
<Form>
<Field type="email" name="email" placeholder="Email" />
<Field as="select" name="color">
<option value="red">Red</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
</Field>
<Field name="firstName" let:field let:meta>
<div>
<input
type="text"
placeholder="Jon"
{...field}
on:input={field.handleInput}
on:blur={field.handleBlur}
/>
{#if meta.touched && meta.error}
<div className="error">{meta.error}</div>
{/if}
</div>
</Field>
<Field name="lastName" placeholder="Doe" as={MyInput} />
<button type="submit">Submit</button>
</Form>
</Sveltik>
</div>
as?: string | Componentname: stringvalidate?: (value: any) => undefined | stringlet:field: FieldInputPropslet:form: SveltikBaglet:meta: FieldMetaPropsas?: string | ComponentEither a Svelte component or the name of an HTML element to render. Supports the following:
inputselecttextareaSvelte components must export let the props that they expect to be passed.
The available props are match the let:props (see below). Also is passed an additional prop
props which contains all additional props passed to <Field />.
name: stringA field's name in Sveltik state. Required.
validate?: (value: any) => undefined | stringYou can run independent field-level validations by passing a function to the validate prop.
The function will respect the validateOnBlur and validateOnChange config/props specified in the <Field>'s parent <Sveltik>.
If invalid, return a string containing the error message or return undefined.
let:field: FieldInputPropsAn object that contains:
name: string - The name of the fieldvalue: any - The value of the fieldhandleInput: (e: HTMLInputEvent) => void - Input handler to be bound with on:inputhandleBlur: (e: HTMLBlurEvent) => void - Blur handler to be bound with on:blurlet:form: SveltikBaglet:meta: FieldMetaPropsAn object that contains:
initialError?: string - The field's initial error if the field is present in initialErrorsinitialTouched?: boolean - The field's initial value if the field is present in initialTouchedinitialValue?: any - The field's initial value if the field is given a value in initialValuesinitialWarning?: string - The field's initial warning if the field is given a value in initialWarningserror?: string - The field's error messagetouched?: boolean - Whether the field has been visitedvalue?: any - The field's valuewarning?: string - The field's warning messageon:input, on:blur instead of spread attributes.<Form />Form is a small wrapper around an HTML <form> element that automatically hooks into Sveltik's handleSubmit and handleReset.
All other props are passed directly through to the DOM node.
// so...
<Form />
// is identical to this...
<form on:reset={props.handleReset} on:submit={props.handleSubmit} {...props} />
<ErrorMessage /><ErrorMessage /> is a component that renders the error message of a given field
if that field has been visited (i.e.touched[name] === true) (and there is an error message present).
It expects that all error messages are stored for a given field as a string.
as?: string | Componentname: stringlet:msg: stringas?: string | ComponentEither a Svelte component or the name of an HTML element to render.
If not specified, <ErrorMessage /> will just return a string.
Svelte components must export let the props that they expect to be passed.
The available props are match the let:props (see below).
Also is passed an additional prop props which contains all additional props passed to <ErrorMessage />.
name: stringA field's name in Sveltik state. Required.
let:msg: stringA field's error message.
as prop instead of component for consistency with <Field /><ScrollMarker /><ScrollMarker /> marks the DOM scroll position of a form element in the document.
It renders a zero-height div. Useful for scrolling to the first field with an error.
name: stringname: stringA field's name in Sveltik state. Required.