This is a client-side form library for Svelte. It's super early in developement so expect bugs, changes, and dragons.
Demo app: https://pluma-svelte-forms.netlify.app/
To install:
npm i pluma-svelte-forms
- Less than 3kB gzip.
- No dependencies (other than Svelte).
- The DOM is the ultimate source of truth for values. You have total freedom to modify the DOM for complex forms. This library will figure it out.
- You can use in-browser native validation for the most common use cases (eg: required fields).
- Validation is sync (custom or native).
- You can add per-field external validation. This allows you to implement cancealable async validators.
- Control when errors are displayed to tailor the user experience.
<script>
import {controller} from 'pluma-svelte-forms';
import {writable} from 'svelte/store';
const settings = {
async onSubmit (values) {
console.log(values)
}
}
</script>
<form use:controller={settings}>
<input type="email" name="email" required>
<input type="password" name="password" required>
<button type="submit">Submit</button>
</form>
Validation happens on every event (input
, blur
, etc). The controllerState
is always updated with the current state of the complete form. Check the demo app to get an idea of what this means.
Once a field is considered to be valid or invalid, its input will be marked with a CSS class. By default these are valid
and invalid
but you can configure custom CSS class names (eg: is-valid
and is-invalid
if you're using Bootstrap).
You can completely deactivate this behavior by using null
for the validClass
and/or invalidClass
settings.
The valid CSS class will not be applied to checkboxes, select, and radio inputs. You can change this behavior with the addValidClassToAllInputs
setting.
Other than the CSS classes mentioned before, this library will not display any errors for you.
You can pass a Svelte writable on the initial configuration which will be updated with the currently displayed errors.
Although the library knows the state of the complete form at all times, errors are not always displayed. There's nothing more annoying than a form nagging you about an incorrect email address when you haven't finished writing it.
This is the default behavior:
- Errors are always displayed when submitting the form.
- Errors are never displayed when interacting with the form.
- If a field is displaying an error, it will be hidden once the user changes the field's value.
blur
andfocus
events will not hide an error.
See the settings below on customizing the default behavior.
When using the external validation on a field, the library will ignore all the error displaying logic and you will have total control on when to display an error.
When configuring a field you can add any number of sync validators:
function isAllCaps (value) {
const regexLowercase = /[a-z]/;
const testLowercase = regexLowercase.test(value);
if (testLowercase) return 'Only use uppercase letters';
return true;
}
const formControllerSettings = {
async onSubmit (values) {},
fields: {
titleInCaps: {
validators: [isAllCaps]
}
}
}
In your validator, return true
if the value is valid. Anything other than true
will mark the field as invalid, and whatever you return will be available in the controllerState
and displayedErrors
stores.
You can add a per-field external validator which will have full control over the validation of a field:
function checkDomainIsAvailable (fieldState, eventType, update) {
// do your thing
}
const formControllerSettings = {
async onSubmit (values) {},
fields: {
domain: {
externalValidator: checkDomainIsAvailable
}
}
}
fieldState
is the current state of the field (value, etc)eventType
is whatever event that triggered the external validator ('submit', 'input', etc).update
is a function you can use to update the state of the field such as marking it valid, invalid, etc.
See the async validation form for a full example on how to implement async validation with promise cancelation.
Because the DOM is the source of truth, you can alter it in any way you need. You can add and remove fields dynamically and the state of the library will be updated magically.
See the dynamic form demo for an example of a dynamic form.
Field settings are connected to a particular input using its name attribute. This works for the vast majority of use cases, but there are more complex scenarios where this breaks.
For example, imagine you had a field called productName
with a custom validator to ensure the name is properly formatted:
const formControllerSettings = {
async onSubmit (values) {},
fields: {
productName: {
validators: [checkNameFormat]
}
}
}
By default, the productName
settings would only be applied to this input:
<input type="text" name="productName"/>
But what if you wanted to edit multiple products in the same form? What if the number of products was dynamic and you didn't know how many you'd want to edit?
The solution is using name aliases so that you can apply a particular setting to any input:
<input type="text" name="productName|3b761efe-f253-484c-9b56-febf9dcb7268"/>
<input type="text" name="productName|f52ddac8-d46a-42cd-9de3-f84275e786b2"/>
<input type="text" name="productName|9329ff26-90e7-4b01-a1c8-f0ef0d0b0d3a"/>
Now all those inputs will use the productName
settings, but will be treated as different inputs with their own name. In this example, the product id.
See the dynamic form with custom validation demo for a full example on how to use aliases.
Required:
onSubmit
a callback function that will be triggered when all validation has passed and the form is submitted.
Optional:
fields
an object with field configurationsvalidClass
custom CSS class that will be applied to valid input elements. The default isvalid
. If set tonull
no class will be applied.invalidClass
custom CSS class that will be applied to invalid input elements. The default isinvalid
. If set tonull
no class will be applied.useNativeErrorTooltips
use the browser's error tooltips. Defaults tofalse
.displayedErrors
a Svelte writable that will be updated with displayed errorscontrollerState
a Svelte writable that will be updated with the controller statedisplayErrorsOnBlur
display field errors onblur
events. The default isfalse
.displayErrorsOnChange
display field errors onchange
andinput
events. The default isfalse
.hideErrorsOnChange
hide field errors onchange
andinput
events. The default isfalse
.addValidClassToAllInputs
add thevalidClass
too all types of inputs. The default isfalse
.
All optional:
validators
an array with sync functions that will be used to validate the value of the field after the native validators have passed.externalValidator
a sync function that will be used for all validation. When using this option, no validation will be performed by the library itself.displayErrorsOnChange
show field errors oninput
andchange
events. The default isfalse
.