colinaut / alpinejs-plugin-simple-validate

Simple Alpine form validation plugin
97 stars 4 forks source link

AlpineJS Plugin — Simple Form Validation

Very simple form validation plugin for AlpineJS. This plugin is designed, like AlpineJS itself, to be sprinkled in as needed. What this plugin does not do is impose an opinionated structure for your form data or functionality. It can be used with or without x-model.

The x-validate directive allows for simple validation and error display. It also captures all form data in a reactive formData. The $validate magic function grants access to validation functions, formData, and simple submit validation check.

Update 1.8

Simple Usage

Add a x-data, and x-validate to your <form> element (you don't need any variables on x-data ; it just needs to be initiated as an Alpine component). This automatically:

Custom Usage

Directive x-validate

Form Element Directives and UI Modifiers

The UI modifiers are mainly for setting global defaults on <form> but you can also be used on individual form field elements for more specific control.

Field Element Directives

These are bonus directives for built in regex validation. You can also ignore these and use the pattern attribute with your own regex.

Used on <input>, <select>, <textarea>

* this allows you to use x-validate.required instead of required attribute or x-validate.tel on type='text' instead of type='tel'

Using Expressions for Validation

You can add a specific test to a field like x-validate='$el.value === 'bunny'; this can be paired up with other validations. For example: x-validate.website='$el.includes('bunny') for only websites with the word bunny in the name. _Note that in many cases the normal pattern attribute may be all you need._

Checkbox and Radio Button Groups

Checkboxes and radio buttons that share the same name attribute update the same formData field data object. Radio buttons update the value with the currently selected button. Checkboxes save as both a comma separated string value and as an array.

You can validate that at least one is selected by adding x-validate.group to every checkbox or radio button in a named group. If you want the user to select multiple checkboxes, use an added expression with the minimum number x-validate.group="2".

Note: Checkbox and radio button groups add their error message after the wrapper for the group. This is either the closest field-parent class parent element or it uses .parentNode.parentNode by default. It's assumed that each checkbox/radio is wrapped in a label or list item, and then has a wrapper around the group.

Magic functions

Validation Functions

You can add any specific validation like email or tel. Main difference between the magic function and the directive is that required is assumed.

Other Functions

When used on <form>, the x-validate every field is added to a reactive formData[formId] array. If only used on individual fields, x-validate only adds those fields to the formData[formId] array.

* 'el' argument variable works with either $refs or a string of the name/id for getting data from form, fieldset, and fields.

Advanced Functions

These grant access to some of the backend functions — use at your own risk.

Example formData

{
    'field-name': {
        name: 'field-name', node: [field HTMLElement], value: 'field value', valid: true, required: true, mods: [array of directive modifiers], set: [parent fieldset HTMLElement], parentNode: [parent HTMLElement], array: [array of checked selections (only used groups of checkboxes or radio buttons)], exp: [expression on x-validate]
    }
}

Note: name = name attribute || id attribute

Example

More complicated examples in examples folder. run npm run serve to view.

<form id="form" x-data x-validate.validate-on-submit action="/api/end-point" method="post">
        <p><em>* required</em></p>
        <div>
            <label for="name">Your Name *</label>
            <input type="text" id="name" name="name" required />
        </div>
        <div>
            <label for="email">Your Email *</label>
            <input type="email" id="email" name="email" required />
        </div>
        <div>
            <label for="wholenumber">Whole Number</label>
            <input type="wholenumber" id="wholenumber" name="wholenumber" x-validate.wholenumber data-error-msg="positive whole number required" />
        </div>
        <div id="animals" data-error-msg="you must pick at least one animal">
            <h4>Favorite Animals *</h4>
            <label><input type="checkbox" x-validate.group name="animal" id="cat" value="cat" /> 
                Cat</label>
            <label><input type="checkbox" x-validate.group name="animal" id="dog" value="dog" /> 
                Dog</label>
            <label><input type="checkbox" x-validate.group name="animal" id="bunny" value="bunny" /> 
                Bunny</label>
        </div>
        <div>
            <input type="submit" value="submit">
        </div>
    </form>
<style type="text/css">
    /* style to display the error message */
    .error-msg {
        color: red;
    }
</style>

The above example will validate using x-validate prior to submitting. If you need to submit using javascript, then you can use alpine for this as such:

<form id="form" x-data x-validate.validate-on-submit 
  @submit.prevent="if ($validate.isComplete('form')) yourPostFormFunctionHere($validate.value('form'))" >

Example of more elaborate error message styling

.error-msg[hidden] {
    opacity: 0;
    height: 0px;
    transform: scale(0);
}
.error-msg {
    font-size: 0.8rem;
    font-weight: 700;
    color: darkred;
    transform-origin: left;
    transition: all 200ms;
    display: block;
}

Installation

CDN

<script defer src="https://unpkg.com/@colinaut/alpinejs-plugin-simple-validate@1/dist/alpine.validate.min.js"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>

NPM/PNPM/YARN

npm i @colinaut/alpinejs-plugin-simple-validate

pnpm i @colinaut/alpinejs-plugin-simple-validate

yarn add @colinaut/alpinejs-plugin-simple-validate

Bundling and initializing

If you are bundling your javascript then you can initialize the plugin like so:

import Alpine from "alpinejs";
import validate from "@colinaut/alpinejs-plugin-simple-validate";

Alpine.plugin(validate);

window.Alpine = Alpine;

Alpine.start();

Eleventy static site

If you are using Eleventy, and want to install locally rather than rely on the CDN, you can install via NPM/PNPM/YARN and then pass through the js file so that it is included in the output. Then you would just need to add it to the head.

eleventyConfig.addPassthroughCopy({
    "node_modules/alpinejs/dist/cdn.min.js" : "js/alpine.min.js",
    "node_modules/@colinaut/alpinejs-plugin-simple-validate/dist/alpine.validate.min.js": "js/alpine.validate.min.js",
})
<script src="https://github.com/colinaut/alpinejs-plugin-simple-validate/raw/main/js/alpine.validate.min.js" defer></script>
<script src="https://github.com/colinaut/alpinejs-plugin-simple-validate/raw/main/js/alpine.min.js" defer></script>

Roadmap

Feel free to add any enhancement requests on github.

Acknowledgements

Built using AlpineJS plugin blueprint