npm i -D svelte-forms
or
yarn add -D svelte-forms
As of version 1.1.0, the field validation objects are no longer directly located inside of the form validation object but rather in a sub-property of it (fields).
The form function needs a callback that returns a fields configuration object.
<script>
import { form, bindClass } from 'svelte-forms';
let name = '';
const myForm = form(() => ({
name: { value: name, validators: ['required'] }
}));
</script>
<style>
:global(input.invalid) {
border-color: red;
}
</style>
<form>
<input
type="text"
name="name"
bind:value={name}
use:bindClass={{ form: myForm }} />
<button disabled="{!$myForm.valid}">Login</button>
</form><script>
import { form } from 'svelte-forms';
let name = "";
let email = "";
const usernameIsNotTaken = async value =>
fetch(`https://jsonplaceholder.typicode.com/users?username=${value}`)
.then(d => d.json())
.then(d => ({
name: "usernameIsNotTaken",
valid: !d.length
}));
const loginForm = form(
() => ({
name: {
value: name,
validators: ["required", "min:6", usernameIsNotTaken]
},
email: { value: email, validators: ["required", "email"] }
}),
{
initCheck: true,
validateOnChange: false,
stopAtFirstError: false,
stopAtFirstFieldError: false
}
);
</script>
<form>
<input type="text" bind:value={name} />
{#if $loginForm.fields.name.errors.includes('required')}
<p>The name is required</p>
{/if}
{#if $loginForm.fields.name.errors.includes('min')}
<p>The name should be at least 6 characters</p>
{/if}
{#if $loginForm.fields.name.pending}
<p>Checking name availability..</p>
{/if}
{#if $loginForm.fields.name.errors.includes('usernameIsNotTaken')}
<p>This username is already taken</p>
{/if}
<input
type="email"
bind:value={email}
class:valid={$loginForm.fields.email.valid} />
{#if $loginForm.fields.email.errors.includes('email')}
<p>The email is invalid</p>
{/if}
<button on:click|preventDefault={() => loginForm.validate()}>
Validate form
</button>
<button disabled={!$loginForm.valid}>Login</button>
</form>Creates a new form validator and returns a store observable, thus you can automatically subscribe with the famous $ reserved token.
The store value represents a form validation object.
As second parameter you can pass a configuration object with the following properties
| property | description |
|---|---|
stopAtFirstError |
Stops validation after first error encountered. Default: false |
stopAtFirstFieldError |
Stops validation after first error encountered per field. Default: true |
initCheck |
Tells the form to validate or not the fields at initialization. Default: true |
validateOnChange |
Tells the form to validate after changes to fields. Default: true |
The form comes with a handy function validate that performs a validation on call.
const myForm = form(() => ({ name: { value: '', validators: ['required'] } }));
function manualValidation() {
myForm.validate();
}bindClass({ form: StoreObservable, name: string, valid: string = 'valid', invalid: string = 'invalid', dirty: string = 'dirty' })
<input type="text" name="username" use:bindClass={{ form: loginForm }} /> <input type="text" use:bindClass={{ form: loginForm, name: "username" }} />
Automatically adds valid or invalid and dirty (default value) classes to the input:
- Adds
validorinvalidIF the form is dirty AND every rule is matched. - Adds
dirtyif field is dirty.
If bindClass is used on a DOM node that has an attribute name, it will check for this field.
Otherwise you can set the field by setting the name parameter.
You can override the classes by passing the parameters valid and invalid.
<input type="text" use:bindClass={{ form: loginForm, valid: 'ok', invalid: 'ko' }} />
The keys of the object represent the name of the fields and their validator configurations
{ name: { value: name, validators: ['required'], enabled: true, ...data } }| property | description |
|---|---|
value |
Reference the value to be check |
validators |
An array representing the validations that need to be performed on the field. See @validators |
enabled |
Boolean defining if the field should be included in the validation process. Default true |
Additional data may be included here (but has no effect).
| property | type | description |
|---|---|---|
valid |
boolean | If the form is valid or not |
dirty |
boolean | If any field has a different value than when the form was initialized |
fields |
Object | An object where the keys are the names as described in the fields configuration object and their respective field validation objects which represent the current state of the form |
oldFields |
Object | An object where the keys are the names as described in the fields configuration object and their respective field validation objects which represent the last state of the form |
let name = '';
const loginForm = form(() => ({
name: { value: name, validators: ['required', 'min:3'], extraData: '' }
}));
// Form
$loginForm.valid; // false
$loginForm.dirty; // false
// Current state of name field
$loginForm.fields.name.valid; // false
$loginForm.fields.name.pending; // false
$loginForm.fields.name.errors; // ['required', 'min']
$loginForm.fields.name.enabled; // true
$loginForm.fields.name.data; // { value, validators, extraData }```An object that represents a validated field.
| property | type | description |
|---|---|---|
valid |
boolean | If the field is valid or not |
errors |
Array | An array representing the errors name in case if the field is invalid |
pending |
boolean | If there are any async validators, will be true until all of them have been resolved |
enabled |
boolean | If the field is enabled or not |
data |
object | The validator configuration object |
{ validators: ['between:3:16'] }`
If the value is a number, checks the number is between numberA and numberB
If the value is a string, checks the string length is between numberA and numberB
{ validators: ['email'] }`
Check the value is an email
{ validators: ['equal:42'] }`
If the value is a number, checks the number is equal to number
If the value is a string, checks the string length is equal to number
{ validators: ['min:42'] }`
If the value is a number, checks the number is greater than number
If the value is a string, checks the string length is greater than number
{ validators: ['max:42'] }`
If the value is a number, checks the number is lesser than number
If the value is a string, checks the string length is lesser than number
{ validators: ['required'] }`
Mark the field as required
{ validators: ['url'] }`
Check the value is an URL
If you want to use your own validator, you can pass a function, it will receive the value to be checked as parameter.
It must return an object as follow: { valid: boolean, name: string }
valid: describes if the condition is matched
name: the name of the validator in case of failure
const empty = value => ({ valid: value === '', name: 'empty' });
{
name: {
value: name,
validators: [empty]
}
}You can of course mix regular validators and custom validators.
Nothing more to do, just mark your function as async or return a Promise.
svelte-forms will handle things for you.
In addition, there will be a pending property inside the field validation object telling if the validator has been resolved or is still pending.
- Testing
- Examples