Writing custom element metadata: Restricting element attributes

Similar to restricting content restricting attributes comes in a few different versions. To define what values attribute accept the attributes property is used, to define what attributes are required use requiredAttributes and to mark an attribute as deprecated use deprecatedAttributes.

Define attribute values

Assuming our <my-component> element has a duck attribute which can take the value huey, dewey or louie we can use the attributes property to define an enumerated list of allowed values:

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      duck: {
        enum: ["huey", "dewey", "louie"],
      },
    },
  },
});

<!-- ok: attribute value is explicitly allowed -->
<my-component duck="dewey"></my-component>

<!-- error: attribute value is not one of the allowed values -->
<my-component duck="flintheart"></my-component>
error: Attribute "duck" has invalid value "flintheart" (attribute-allowed-values)
  3 |
  4 | <!-- error: attribute value is not one of the allowed values -->
> 5 | <my-component duck="flintheart"></my-component>
    |                     ^^^^^^^^^^


1 error found.

We can also specify regular expressions by surrounding the string with / (remember to escape special characters properly):

 import { defineMetadata } from "html-validate";

 export default defineMetadata({
   "my-component": {
     flow: true,
     attributes: {
       duck: {
-        enum: ["huey", "dewey", "louie"],
+        enum: ["/\\d+/"],
       },
     },
   },
 });

<!-- ok: any numerical value is allowed -->
<my-component ducks="3"></my-component>

<!-- error: non-numerical values are disallowed -->
<my-component ducks="huey"></my-component>
error: Attribute "ducks" has invalid value "huey" (attribute-allowed-values)
  3 |
  4 | <!-- error: non-numerical values are disallowed -->
> 5 | <my-component ducks="huey"></my-component>
    |                      ^^^^


1 error found.

TIP

Regular expressions and enumeration can be used at the same time.

To force a boolean value similar to disabled, selected etc instead set the boolean property to true.

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      quacks: {
        boolean: true,
      },
    },
  },
});

<!-- ok: boolean attribute -->
<my-component quacks></my-component>

<!-- error: boolean attribute cannot take value -->
<my-component quacks="duck"></my-component>
error: Attribute "quacks" should omit value (attribute-boolean-style)
  3 |
  4 | <!-- error: boolean attribute cannot take value -->
> 5 | <my-component quacks="duck"></my-component>
    |               ^^^^^^


error: Attribute "quacks" has invalid value "duck" (attribute-allowed-values)
  3 |
  4 | <!-- error: boolean attribute cannot take value -->
> 5 | <my-component quacks="duck"></my-component>
    |                       ^^^^


2 errors found.

If the value can be omitted (same as the empty value "") set the omit property to true. This is often combined with enum but it should have a default value.

For instance, to allow the quacks attribute to be set to either duck or dog but at the same time not require a value to be set at all omit can be used.

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      quacks: {
        omit: true,
        enum: ["duck", "dog"],
      },
    },
  },
});

<!-- ok: omitting value is allowed -->
<my-component quacks></my-component>

<!-- ok: value is one of the allowed values -->
<my-component quacks="duck"></my-component>

Required attributes

Required attributes (attributes that must be set on an element) can be specified by setting required to true:

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      duck: {
        required: true,
      },
    },
  },
});

<!-- ok: attribute is present -->
<my-component duck="dewey"></my-component>

<!-- error: attribute is omitted -->
<my-component></my-component>
error: <my-component> is missing required "duck" attribute (element-required-attributes)
  3 |
  4 | <!-- error: attribute is omitted -->
> 5 | <my-component></my-component>
    |  ^^^^^^^^^^^^


1 error found.

Pattern attributes

Attribute keys containing * are treated as glob patterns matching one or more characters (case-insensitive). For example, "custom-*" matches custom-foo, custom-bar, etc.

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      "custom-*": {},
    },
  },
});

See the element metadata reference for details.

Deprecating attributes

Similar to required attribute we can set deprecated to true or a message to mark an attribute as deprecated:

import { defineMetadata } from "html-validate";

export default defineMetadata({
  "my-component": {
    flow: true,
    attributes: {
      duck: {
        deprecated: true,
      },
    },
  },
});

<!-- error: uses deprecated attribute -->
<my-component duck="dewey"></my-component>

<!-- ok: omitted deprecated attribute -->
<my-component></my-component>
error: Attribute "duck" is deprecated on <my-component> element (no-deprecated-attr)
  1 | <!-- error: uses deprecated attribute -->
> 2 | <my-component duck="dewey"></my-component>
    |               ^^^^
  3 |
  4 | <!-- ok: omitted deprecated attribute -->
  5 | <my-component></my-component>


1 error found.