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' })
<input type="text" name="username" use:bindClass={{ form: loginForm }} /> <input type="text" use:bindClass={{ form: loginForm, name: "username" }} />
Automatically adds valid
or invalid
(default value) classes to the input IF
the form is dirty AND every rule is matched.
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