npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

be-formidable

v0.0.18

Published

Add additional validations on form element beyond those that can be specified on an individual field level.

Downloads

90

Readme

be-formidable (🥷)

Playwright Tests How big is this package in your project? NPM version

None Shall Pass

Add additional validations on the form element, beyond those that can be specified on an individual field level.

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": ["@url", "@file"],
            "invalidCssClass": "no-url-or-file-selected"
        }
    ]
}'>
    <label>
        URL:
        <input name=url id=url type=url>
    </label>
    <label>
        File:
        <input name=file id=file type=file>
    </label>
</form>

Attaching this enhancement / behavior results in overriding the checkValidity() method of the form element. Calls to checkValidity has the added side-effect of modifying css classes on the form element. If the validations fail, css class "invalid" is added to the form element. Otherwise "valid" is added. In addition, if the "invalidCssClass" property is specified, it will get applied to the form element, or removed, depending on the validation.

Shorter, alternative names

It is easy to define a custom, (shorter) name for less formal environments. be-formidable is the canonical name, but by referencing an alternative registration file we can use, for example:

<form 🥷🏾='{
    "invalidIf":[
        {
            "noneOf": ["@url", "@file"],
            "invalidCssClass": "no-url-or-file-selected"
        }
    ]
}'>
    <div class=instructions>Please Select a url or a file</div>
    <label>
        URL:
        <input name=url id=url type=url>
    </label>
    <label>
        File:
        <input name=file id=file type=file>
    </label>
</form>

Why two negatives?

It could be argued that validOnlyIf/oneOf is clearer than invalidIf/noneOf. Here's why we chose the more counterintuitive approach:

This component prefers the "innocent until proven guilty" way of thinking, because it feels a bit truer to what it is actually doing, and may more effectively alert the developer to the fact that the form will be considered valid until the be-formidable behavior / enhancement is attached. Before then, it might be prudent to hide/disable any submit buttons, or even hide or obscure the entire form.

JSON-in-html?

Editing JSON-in-html can be rather error prone. A VS Code extension is available to help with that, and is compatible with web versions of VSCode.

And in practice, it is also quite ergonomic to edit these types of attributes in a *.mjs file that executes in (no)de(no) as the file changes, and compiles to an html file via the be-importing compiler, for example. This allows the attributes to be editable with JS-like syntax. Typescript 4.6 supports compiling mts to mjs files, which then allows typing of the attributes. Examples of this in practice are:

  1. xtal-side-nav
  2. xtal-editor
  3. cotus

Specifying property to check for truthiness [TODO]

The specifier for which elements to monitor follows the DSS syntax.

By default, the "value" property is what is used on the element when it is checked for truthiness.

To specify an alternative property to check:

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": ["@keysInPocket.checked", "@havePhone.checked"],
            "invalidCssClass": "not-ready-to-go-out"
        }
    ]
}'>
    <div class=instructions>
        Please take your keys, or at least a phone to call a locksmith.
    </div>
    <label>
        <input name=keysInPocket type=checkbox>
        I have keys in my pocket
    </label>
    <label>
        <input name=havePhone type=checkbox>
        I have a phone
    </label>
</form>

So this syntax is not compatible with form elements that use "." in the name. If encountering a scenario where "." may be in the name, we need to be a bit more verbose:

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": [
                {
                    "name": "keys.in.pocket",
                    "prop": "checked"
                 },
                 {
                     "name": "have.phone",
                     "prop": "checked"
                 }
            ],
            "instructions": "Please take your keys, or at least a phone to call for a locksmith.",
            "invalidCssClass": "Not ready to go out."
        }
    ]
}'>
   ...
</form>

Other validation criteria [Untested]

The rules so far have essentially been providing support for the "required" attribute, but for groups of form elements. But there are other validations that form fields support (min, max, pattern, etc).

Support for such criteria is provided. For example with min:

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": [
                {
                    "name": "firstCustomer Age",
                    "min": 17,
                },
                {
                    "name": "secondCustomer Age",
                    "min": 17,
                },
                {
                    "name": "thirdCustomer Age",
                    "min": 17,
                },
            ],
            "instructions": "No one under the age of 17 is permitted to watch this movie without being accompanied by an adult or guardian"
        }
    ]
}'>
   ...
</form>

NotEquals

<form be-formidable='{
    "validOnlyIf":[
        {
            "atLeastOneOf": [
                {
                    "name": "firstCustomer Age",
                    "min": 17,
                },
                {
                    "name": "secondCustomer Age",
                    "min": 17,
                },
                {
                    "name": "thirdCustomer Age",
                    "min": 17,
                },
            ],
            "equals": [
                {
                    "name": "hiddenCalculatedField"
                },
                {
                    "name": "payment"
                }
            ]
            "instructions": "No one under the age of 17 is permitted to watch this movie without being accompanied by an adult or guardian"
        }
    ]
}'>
   ...
</form>

Specify querySelectorAll() for the elements to be checked

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": [{
                "find": ".my-form-element-group", 
                "prop": "checked"
            }],
        }
    ]
}'>
    ...
</form>

Side effect of calling checkValidity()

"invalidClassesToApply" is an array of strings that is stored at location formElement.beEnhanced.beFormidable.invalidClassesToApply. It lists validation errors.

Specify to monitor for certain events.

As mentioned in the beginning, the examples so far do not result in automatically calling checkValidity (except, by default as soon as the behavior is attached), so nothing will actually happen unless some other script is invoking checkValidity.

We can specify when to automatically call checkValidity.

Simplest:

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": ["url", "file"],
            "message": "Select a url or a file"
        }
    ],
    "checkValidityOn": "input"
}'>
    ...
</form>

If multiple events / optional settings are required:

<form be-formidable='{
    "invalidIf":[
        {
            "noneOf": ["url", "file"],
            "message": "Select a url or a file"
        }
    ],
    "checkValidityOn": [
        "input", 
        {
            "type": "change",
            "options": {
                "capture": true
            }
        }
    ]
}'>
    ...
</form>

Unfortunate headwinds

Unfortunately, the platform does not yet support specifying a custom validation function for a form element.

This means that the :valid and :invalid pseudo-classes are not adjusted as needed.

The be-formidable enhancement does set "valid" or "invalid" classes during the checkValidity() calls.

Suggested CSS:

<style>
    form:invalid, form.be-formidable.invalid {
        border: 5px solid red;
    }
    form:valid, form.be-formidable.valid {
        border: 5px solid green;
    }
</style>

Viewing Locally

Any web server that serves static files will do but...

  1. Install git.
  2. Fork/clone this repo.
  3. Install node.
  4. Open command window to folder where you cloned this repo.
  5. npm install

  6. npm run serve

  7. Open http://localhost:8000/demo in a modern browser.

Importing in ES Modules:

import 'be-formidable/be-formidable.js';

Using from CDN:

<script type=module crossorigin=anonymous>
    import 'https://esm.run/be-formidable';
</script>