Elements and attributes

Use global attributes, boolean attributes and data-* correctly, and know what may nest inside what.

03of 22
≈ 11Min read
8Parts

The rules of an attribute

An attribute is written in the opening tag as name="value". Attribute names are case-insensitive, so CLASS and class are the same thing — write them in lower case and never think about it again.

Quote every value. Unquoted values work until the value contains a space, and then the rest of it silently becomes another attribute.

what unquoted values do
<div class=card wide>      <!-- class="card" and an attribute called "wide" -->
<div class="card wide">    <!-- two classes, as intended -->

Boolean attributes

Some attributes are on or off, and their presence is what counts. disabled="false" is still disabled — the value is ignored entirely. To turn one off, remove it.

  • Common ones: disabled, checked, required, readonly, multiple, selected, hidden, open, autofocus, async, defer, novalidate, playsinline, muted, loop, controls.
all three mean the same thing
<input disabled>
<input disabled="">
<input disabled="disabled">

<!-- this one is ALSO disabled -->
<input disabled="false">
In JavaScript

Set them as properties, not strings: input.disabled = false. Using setAttribute("disabled", false) adds the attribute and disables the field.

The global attributes

AttributeWhat it does
idA unique address for one element. Used by labels, anchors and getElementById.
classOne or more names, space separated. The main hook for CSS.
styleInline CSS. Beats a stylesheet, so use it sparingly.
titleA tooltip on hover. Invisible on touch and to keyboard users — never the only place information lives.
hiddenRemoves the element from the page and from assistive technology.
langThe language of this element and its children.
dirltr, rtl or auto — text direction.
tabindexWhether and where the element sits in the keyboard order.
contenteditableMakes the content editable in place.
data-*Your own data. The browser ignores it entirely.
inertThe element and everything inside it stop responding to clicks and focus.

id and class

  • An id must be unique in the document. Two elements with the same id is not an error the browser reports — it just quietly uses the first one.
  • An id may not contain spaces. Keep it to letters, digits and hyphens so it works in CSS and in a URL fragment.
  • A class may repeat as often as you like, and one element may carry several: class="card card--wide is-open".
  • Use class for styling and id for addressing: a label's for, an anchor target, an aria-labelledby.

Your own data

Anything beginning with data- is yours. HTML ignores it, CSS can select on it, and JavaScript reads it from dataset with the name converted from kebab-case to camelCase.

markup
<button class="tab" data-panel="specs" data-open-delay="200">Specification</button>

Reading it back

Every value is a string. Convert it yourself, and remember that a data- attribute is visible to anyone who opens developer tools — it is not a place for secrets.

script.js
const b = document.querySelector(".tab");

b.dataset.panel;        // "specs"
b.dataset.openDelay;    // "200"  — always a string
Number(b.dataset.openDelay);   // 200

b.dataset.state = "active";    // adds data-state="active"

What may go inside what

HTML elements belong to content categories, and each element states what it will accept. The two you meet constantly are flow content — most things, including block-level elements — and phrasing content: text and the elements that mark up text.

A <p> accepts phrasing content only. Put a <div> or an <h2> inside one and the browser closes the paragraph before it, which is why your CSS then applies to an element that no longer contains what you thought.

what the browser builds
<!-- you wrote -->
<p>Intro <div>Block</div> more</p>

<!-- the DOM you get -->
<p>Intro </p>
<div>Block</div>
 more<p></p>
Other pairs that bite

<ul> and <ol> accept only <li>. <tr> accepts only <td> and <th>. An <a> may not contain another <a>, and a <button> may not contain a link or another button.

Case, whitespace and the rest

  • Tag and attribute names are case-insensitive; write them lower case. Attribute values usually are case-sensitive — class names and ids definitely are.
  • Any run of whitespace collapses to one space when rendered. Indent your source freely.
  • The four characters to escape in text are &lt;, &gt;, &amp; and, inside a double-quoted attribute, &quot;.
  • Attributes on the same element must not repeat. A second class on one tag is ignored.

Practice