Reputation: 29453
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:
data-*
attributedata-*
attributeconst 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.
B) Custom attributes may only be used in custom elements. They are invalid elsewhere.
C) Data-* attributes are for standard elements, custom attributes are for custom elements.
D) Custom attributes are not even a thing. Where did you get this idea from?
To illustrate my question above, I'd like to give an example of where custom attributes appear not to be valid:
Select text input
Enter:
<!DOCTYPE html>
<html lang="">
<head>
<title>Test</title>
</head>
<body>
<div data-inverted="false">i</div>
<div inverted="false">ii</div>
</body>
</html>
The validator returns the error:
Error: Attribute
inverted
not allowed on elementdiv
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 (?)
Upvotes: 2
Views: 517
Reputation: 21163
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.
Upvotes: 2