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

inputid

v0.1.3

Published

A value object representing an HTML form control ID, making sure the ID generation is deterministic and unique in a document.

Downloads

8

Readme

InputId

npm version Build Status codecov Codacy Badge Open Source Helpers Buy me a coffee

A Javascript value object representing an HTML form control ID, making sure the ID generation is deterministic and unique in a document.

:triangular_flag_on_post: Table of contents

:thinking: Why?

According to the W3C Web Accessibility Tutorials website:

Whenever possible, use the label element to associate text with form elements explicitly. The for attribute of the label must exactly match the id of the form control.

Usually, the exact ID is a detail that is not important for a project specification. It might be anything, assuming it's unique and valid.

Also, writing HTML forms can be tedious, crufty and error-prone. It might be better to abstract the repeatitive code, for instance, using a component. If you're using, for instance, Vuejs, and you're required to specificy an ID, you'd have to do something like this:

<checkbox
    id="form_colors_red"
    label="Colors"
    name="colors"
    value="red"
    v-model="form.colors" />

If someone is implementing form controls dynamically (ex: a component for form input fields), it might be a good idea to generate the IDs automatically instead, especially if it's part of a library.

It might seem a good idea to generate IDs randomly or sequentially, but there's a collision risk that might cause undesirable consequences which are very hard to be detected. Also, if the result is not deterministic, it's hard to retrieve a specific element by its ID. And it would be nice if the IDs are user-friendly and valid ID in the HTML document.

InputId was implemented to solve all those hurdles.

:art: Features

  • Deterministic ID generation based on HTML element attributes
  • Unique ID generation in a document
  • ID sanitization according to the document type
  • Removal of characters that might be problematic in CSS selectors
  • ID generation to find an element by its ID attribute or its related labels

:rocket: Installation

Using npm:

npm install inputid

:feet: Usage

An InputId instantiation is a value object representing a form control ID. It should be immutable and can be used as a String.

It doesn't require any arguments or configuration:

const InputId = require('inputid');

labelElement.htmlFor = inputElement.id = new InputId();

But you'd get better results if an HTML element or options are provided as an argument.

Generating an ID from a HTML element

If the InputId is instantiated with a HTMLElement instance as an argument, it will generate a unique element ID in the element's document which can be used as the element's ID attribute:

inputElement.id = new InputId(inputElement);
labelElement.htmlFor = element.id;

Generating IDs for several elements

It's possible to loop several elements in a document and set their id attribute values with InputId:

const elements = document.getElementsByTagName('input');
elements.forEach(element => {
    element.id = new InputId(element);
    element.parentNode.getElementsByTagName('label')[0].htmlFor = element.id;
});

Generating an ID without an element

InputId also accepts several options as an argument:

inputElement.id = new InputId({
    prefix: 'form-personal-info',
    type: 'radio',
    name: 'gender',
    value: 'male'
});
labelElement.htmlFor = element.id;

The type value is the element type attribute value or the element tagName. The type and value options are redundant if the element is neither a radio button, nor a checkbox, nor an option element.

The prefix should be the form ID attribute value, but that is not enforced.

Generating an ID for an element that does not have a name

Usually, a form control has at a least name:

const element = document.createElement('input');
element.dataset.name = 'cpr';
element.id = new InputId(element);

But sometimes there are good reasons to not have a name. For instance, some value must be a number, but the input field shown to the user should be a formatted text. In that case, the formatted text shouldn't be submitted, and form controls lacking a name are not submitted. It's easy to handle those case by providing a name in the InputId construction arguments besides the element which lacks the name attribute:

const hiddenElement = document.createElement('input');
hiddenElement.name = 'cpr';
const visibleElement = document.createElement('input');
hiddenElement.type = 'text';
visibleElement.id = new InputId({
    element: visibleElement,
    name: 'cpr'
});

Finding an element by its ID

It's easy to find an element by its ID if the options used to instantiate InputId is known (but forceUniqueness must not be true):

const inputId = new InputId({
    prefix: 'form-personal-info',
    type: 'radio',
    name: 'gender',
    value: 'male'
});
const element = inputId.getElement();
const label = inputId.getLabels()[0];

Making sure the ID is unique

There shouldn't exist elements with the same name and value in a form, but if (for some reason) that's a possibility, make sure "the forceUniqueness option value is true:

inputElement.id = new InputId({
    prefix: 'form-personal-info',
    type: 'radio',
    name: 'gender',
    value: 'male',
    forceUniqueness: true
});
labelElement.htmlFor = element.id;

If an HTML element is not provided (as the constructor argument or an option), forceUniqueness is false by default.

Generating more IDs from an ID

Each InputId instantiation is immutable, but it can produce modified copies with method chaining:

const baseId = new InputId({prefix: 'form-personal-info'})
    .forceUniqueness();
nameElement.id = new InputId({name: 'name'});
genderElement.id = baseId
    .withType('radio')
    .withName('gender')
    .withValue('male');

Dealing with problematic characters

In HTML4, an "id" attribute value must:

begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".")

To conform to that specification, if the document is not an HTML5 document, all the invalid characters are removed or replaced. If the first character is not a letter, a prefix is added.

In any case, some characters are always replaced to avoid possible issues in CSS selectors. It's also guaranteed the generated ID is not empty at least using a fallback (by default it's the letter "f"), which can be changed:

const element = inputElement.id = new InputId({
    fallback: 'hidden_name'
});

:wrench: Contributing

Improvements and suggestions are welcome.

Before sending a pull request, make sure all the tests pass after changing the code:

npm test

The test implementations are inside the ./tests folder.

:scroll: License

ISC (see the LICENSE.txt file)