1

Until recently, whenever I've needed a custom attribute in my HTML, I've always used an HTML data-* custom attribute.

Having recently started experimenting with WebComponents and, specifically, Custom Elements, I have started thinking in terms of custom attributes which are not HTML5 data-* custom attributes.

Before inadvertently adopting any non-recommended practices, I would like to clarify the following...

In the list below we have 4 elements:

  • Element i is a standard element with a data-* attribute
  • Element ii is a standard element with a custom attribute
  • Element iii is a custom element with a data-* attribute
  • Element iv is a custom element with a custom attribute

const toggleDataAttribute = (e) => {
    e.target.dataset.inverted = (e.target.dataset.inverted === 'true') ? 'false' : 'true';
}

const toggleCustomAttribute = (e) => {
  if (e.target.getAttribute('inverted') === 'true') {
    e.target.setAttribute('inverted', 'false');
  }

  else {
    e.target.setAttribute('inverted', 'true');
  }
}

const toggleInvert = (e) => {

  if (e.target.dataset.inverted) {
    toggleDataAttribute(e);
  }
  
  else {
    toggleCustomAttribute(e);
  }
}


// Attach click event TO <div> elements
let divs = [...document.getElementsByTagName('div')];

divs.forEach((div) => div.addEventListener('click', toggleInvert, false));

// Attach click event TO <my-circle> elements
let myCircles = [...document.getElementsByTagName('my-circle')];

myCircles.forEach((myCircle) => myCircle.addEventListener('click', toggleInvert, false));


// Define <my-circle> element
class myCircle extends HTMLElement {
  
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }

  connectedCallback() {
    this.root.appendChild(document.createElement('slot'));
  }
}

customElements.define('my-circle', myCircle);
aside {
  position: absolute;
  top: 0;
  right: 0;
  width: 280px;
  line-height: 24px;
}

div {
  float: left;
  margin: 0 12px 12px 0;
  width: 80px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  font-size: 36px;
  border-radius: 50%;
  cursor: pointer;
}

my-circle {
  display: block;
  float: left;
  margin: 0 12px 12px 0;
  width: 80px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  font-size: 36px;
  background: radial-gradient(#fff, #000);
  border-radius: 50%;
  cursor: pointer;
}

my-circle:first-of-type {
  clear: left;
}


div:nth-of-type(1) {
  background: radial-gradient(rgb(255, 255, 0), rgb(255, 0, 0));
}

div:nth-of-type(2) { 
  background: radial-gradient(rgb(255, 255, 0), rgb(0, 163, 0));
}

my-circle:nth-of-type(1) { 
  background: radial-gradient(rgb(255, 255, 0), rgb(223, 163, 0));
}

my-circle:nth-of-type(2) {
  background: radial-gradient(rgb(255, 127, 127), rgb(255, 0, 0));
}

div[data-inverted="true"],
div[inverted="true"],
my-circle[data-inverted="true"],
my-circle[inverted="true"] {
  filter: hue-rotate(180deg);
}
<div data-inverted="false">i</div>
<div inverted="false">ii</div>

<my-circle data-inverted="false">iii</my-circle>
<my-circle inverted="false">iv</my-circle>

<aside>
<p><strong>Click</strong> on each of the circles on the left to invert their backgrounds.</p>
</aside>

Although the set up above works technically, which of the following is true:

  • A) Custom attributes may be used universally, in standard elements and custom elements.

    • Conclusion: Elements i, ii, iii & iv are all valid
  • B) Custom attributes may only be used in custom elements. They are invalid elsewhere.

    • Conclusion: Elements i, iii & iv are valid, while ii is invalid
  • C) Data-* attributes are for standard elements, custom attributes are for custom elements.

    • Conclusion: Elements i & iv are valid, while ii & iii are invalid
  • D) Custom attributes are not even a thing. Where did you get this idea from?

    • Conclusion: Elements i & iii are valid, while ii & iv are invalid

Added:

To illustrate my question above, I'd like to give an example of where custom attributes appear not to be valid:

  1. Go to: https://validator.w3.org/nu/#textarea

  2. Select text input

  3. Enter:

<!DOCTYPE html>
<html lang="">
<head>
<title>Test</title>
</head>
<body>

<div data-inverted="false">i</div>

<div inverted="false">ii</div>

</body>
</html>
  1. Check the markup

The validator returns the error:

Error: Attribute inverted not allowed on element div at this point.

From line 10, column 1; to line 10, column 22

i</div>↩↩<div inverted="false">ii</di

Though... I'm not sure if the tool at https://validator.w3.org/nu/ is outdated and / or abandoned and the Error returned should no longer be regarded as an error in 2020 (?)

TylerH
  • 20,799
  • 66
  • 75
  • 101
Rounin
  • 27,134
  • 9
  • 83
  • 108

1 Answers1

1

All 4 usages work, so why should they be invalid?

data- prefix gives the added bonus they are available in element.dataset.

-- Attributes are Attributes -- , nothing special in the Custom Elements API,
apart from observedAttributes(). Yes, you can use data-* attributes there to.

note

class myCircle extends HTMLElement {
  constructor() {
    super();
    this.root = this.attachShadow({mode: "open"});
  }
  connectedCallback() {
    this.root.appendChild(document.createElement('slot'));
  }
}

can be written as:

class myCircle extends HTMLElement {
  constructor() {
    super()
      .attachShadow({mode: "open"})
      .append(document.createElement('slot'));
  }
}

because super() returns 'this'
and attachShadow both sets and returns this.shadowRoot for free
you are not doing anything with appendChild() return value, so append() (which can take multiple parameters) is enough.

Also note there is a toggleAttribute method.

Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
  • Thanks for this, @Danny - very much appreciated. `.toggleAttribute()` is only for Boolean attributes, I think, (yes, you're right, I _did_ use string equivalents of Boolean values in my example, but that may have been over-simplistic). I've noted your excellent point about `attachShadow()` returning `this.shadowRoot`. With respect to validity - it's certainly the case that browsers will generally accept all sorts of invalid and deprecated markup, so having something working in a browser isn't (for me, at any rate) sufficient reassurance that the usage is valid according to the HTML5 spec. – Rounin Oct 12 '20 at 12:31
  • A Custom Element is not something new. It allows **us mortal developers** to extend HMLElement (something previously only Browser vendors could do in their code) Thus everything 'Attributes' from HTMLElement (from the past 25+ years) applies. -- (Apple won't implement *Customized Built-In* Elements, so extending from HTMLElement is all we got in Safari) – Danny '365CSI' Engelman Oct 12 '20 at 13:46
  • There is no Custom Element involved in that validator, it reports error for **every** attribute **but** ``data-`` prefixed. So the conclusion (from only this validator) is: either the Web has been running on incorrect assumptions for the past decades. Or that validator is wrong. To prevent confusion you could ask your question again but without any reference to Custom Elements... since CEs extends from HTMLElement.. and this validator says any custom attribute on a HTMLElement is an error. – Danny '365CSI' Engelman Oct 12 '20 at 15:12
  • 1
    see https://stackoverflow.com/questions/24932391/are-custom-html-attributes-without-data-prefix-a-valid-attribute – Danny '365CSI' Engelman Oct 12 '20 at 15:17
  • To recap; custom attributes won't pass a validator because you can assign **any** custom attribute name you want to an element. A validator can't check if 'any' is valid.. it would have to know evey possible name.. pure logic. Are your custom attributes safe? No, because every other developer can (ab)use them.. but the very same applies to ``data-`` attributes as well. Can you use custom attributes any way you want.. attributes, CSS selectors etc. Yes. – Danny '365CSI' Engelman Oct 12 '20 at 15:24
  • Note: the validator is wrong on Custom Element names. ```` is a valid tag name. – Danny '365CSI' Engelman Oct 12 '20 at 15:28
  • Right, so I think we can safely conclude that the https://validator.w3.org/nu/ validator is an abandoned project and while it may have been perfectly good in 2012, it really isn't now. I really don't know if there exists a validator which handles contemporary HTML5 in 2020. – Rounin Oct 12 '20 at 20:09
  • I would say it validates fine, just can't validate custom attributes (because it can't validate and * (any) value), and doesn't validate custom-elements with UniCode. – Danny '365CSI' Engelman Oct 13 '20 at 07:18
  • 1
    Found [this on UnknownElements](https://stackoverflow.com/questions/10830682/is-it-ok-to-use-unknown-html-tags/27869027#27869027) which IMHO applies to "attributes" as well. Quote: *Validators are great for people who aren't comfortable with HTML and need guidance. If you're comfortable taking guidance from the spec and from browser implementations, there's no reason to worry about being flunked by the validator. This is absolutely an okay thing to do, so long as you're doing it deliberately and you know enough about what you're doing.* – Danny '365CSI' Engelman Oct 15 '20 at 12:10
  • Yes, I think that's fair enough - validators can, occasionally, produce false negatives. The bigger issue here is that, in the absence of a validator, I can't find any clarification in the WHAT-WG spec regarding the status of custom attributes. – Rounin Oct 15 '20 at 19:20
  • 1
    Yes, the wording is a bit bit weird... https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 : *Attribute names must consist of **one or more characters other than**: SPACE " '>, / =* – Danny '365CSI' Engelman Oct 16 '20 at 08:02