Global Attributes

Learn the HTML attributes that can be applied to almost any element — id, class, style, title, hidden, lang, dir, tabindex, data-*, contenteditable, draggable, spellcheck, and translate — and when each is the right tool.

Most HTML attributes are specific to one element — src only makes sense on <img> or <script>, href only on <a> or <link>. But a set of attributes, called global attributes, work on virtually every HTML element, regardless of tag. Knowing this toolbox well means you can reach for the right attribute instead of reinventing behavior with extra JavaScript or CSS classes.

The essentials: id, class, style, title

id gives an element a unique identifier within the page — used for CSS targeting, JavaScript lookups (getElementById), and as a jump target for URL fragments (#section-id). An id must be unique; only one element on the page may use a given id value.

class assigns one or more (space-separated) names to an element, used for CSS styling and JavaScript selection. Unlike id, many elements can share the same class, and one element can have multiple classes.

style applies inline CSS directly to a single element. It's convenient for quick prototyping or dynamically-set values from JavaScript, but it's generally discouraged for anything maintainable — inline styles are hard to override, hard to reuse, and mix concerns that a stylesheet keeps separate.

title provides advisory text shown as a small tooltip when the user hovers the element. It's supplementary, not a replacement for visible or accessible labeling — screen reader support for title is inconsistent, so critical information shouldn't live only there.

Visibility, language, and reading direction

hidden is a boolean attribute that removes an element from rendering entirely (roughly equivalent to display: none), while also communicating to assistive technology that the content isn't currently relevant — semantically stronger than just hiding something with CSS alone.

lang declares the language of an element's content (e.g. lang="en", lang="fr", lang="es"). Set on <html> it applies to the whole document, letting screen readers choose the correct pronunciation engine and letting browsers offer accurate translation. It can also be set on individual elements for content in a different language than the surrounding page.

dir sets text direction: ltr (left-to-right, the default for most languages), rtl (right-to-left, for languages like Arabic or Hebrew), or auto (browser detects direction from the content).

Keyboard interaction: tabindex

tabindex controls whether and how an element participates in keyboard tab-order navigation. tabindex="0" adds an element to the natural tab order at its position in the document — commonly used to make a custom interactive element (like a <div> acting as a button) keyboard-focusable. tabindex="-1" makes an element programmatically focusable (via JavaScript's .focus()) but removes it from the normal tab sequence — useful for focus management, like moving focus to a modal dialog. A positive tabindex (tabindex="1", "2"...) forces a specific manual tab order, which is almost always an accessibility anti-pattern because it's fragile and conflicts with the document's natural reading order.

Custom data: the data-* attributes

Any attribute prefixed with data- is a custom data attribute — a standards-sanctioned way to attach extra information to an element without inventing non-standard attributes. data-user-id="482" or data-status="pending" can be read easily in JavaScript through the element's .dataset property (element.dataset.userId, element.dataset.status), and styled conditionally in CSS with attribute selectors.

Editable, draggable, and other behavioral attributes

contenteditable="true" makes an element's content directly editable by the user in the browser, like a lightweight rich-text editor — the foundation many WYSIWYG editors are built on.

draggable="true" makes an element participate in the HTML Drag and Drop API, letting users pick it up and drop it elsewhere on the page (in combination with JavaScript drag event handlers).

spellcheck="false" (or "true") controls whether the browser runs its spell-checker against editable content — useful to disable on code input fields, usernames, or other fields where red squiggly underlines are just noise.

Global attributes in use

<div id="profile-card" class="card card--highlighted" title="User profile"
     data-user-id="482" data-status="active" lang="en" tabindex="0">
  <p contenteditable="true" spellcheck="false">Edit this bio...</p>
  <span translate="no">SampleApp</span>
</div>

Code Examples

Hyphenated attribute names (data-item-id) automatically become camelCase properties on .dataset (itemId) — a naming convention built into the DOM API itself.

Because this is a <div>, not a native <button>, it isn't focusable or in the tab order by default. tabindex="0" fixes that — though note this still needs JavaScript to handle Enter/Space key presses, since <div> has no built-in activation behavior the way <button> does.

<button data-action="delete" data-item-id="93">Remove</button>

<script>
  const btn = document.querySelector('button');
  console.log(btn.dataset.action);  // "delete"
  console.log(btn.dataset.itemId);  // "93"
</script>
<div class="custom-toggle" role="switch" aria-checked="false" tabindex="0">
  Notifications
</div>

Important Rules

id values must be unique per page; class values can repeat across many elements.

Avoid positive tabindex values (1, 2, 3...) — they create a fragile, hard-to-maintain tab order that fights the natural document flow.

Prefer external stylesheets over the style attribute for anything beyond quick, temporary, or dynamically-computed values.

Set lang on <html> for every page — it's a baseline accessibility and correctness requirement, not an optional nicety.

data-* attribute names must be lowercase and hyphen-separated; they map to camelCase in JavaScript's .dataset automatically.

In practice

Frameworks like React and Vue lean heavily on data-* attributes for testing hooks (data-testid="login-button") so automated tests can find elements without depending on styling classes that might change. Design systems use data-* for component state too — data-state="open" on a dropdown, styled entirely through a CSS attribute selector like [data-state="open"] { ... } — keeping JavaScript state and CSS presentation cleanly connected.

<div id="item">...</div> <div id="item">...</div> <div id="item-1">...</div> <div id="item-2">...</div>

Duplicate ids are invalid HTML — getElementById and CSS id selectors will only ever find/target the first match, silently breaking any logic that expects to reach the second one.

<div class="btn" tabindex="5">Submit</div> <button class="btn">Submit</button>

Beyond the tabindex anti-pattern, this reinvents a native <button> from scratch, losing built-in keyboard activation, form submission behavior, and correct accessibility semantics for no benefit.

[Choose the Correct Syntax] You need to store a product's numeric SKU (e.g. 48213) on its <div> element so JavaScript can read it later, without inventing a non-standard attribute. Which is correct, standards-compliant HTML? A. <div sku="48213">...</div> B. <div data-sku="48213">...</div> C. <div id="sku-48213">...</div> D. <div class="sku:48213">...</div>

B. <div data-sku="48213">...</div> — Custom data must use the data- prefix (data-sku) to be valid, standards-compliant HTML — a bare custom attribute like sku is not part of the spec, and abusing id or class to smuggle in data values misuses those attributes' actual purposes.

Build a custom 'card' component div that: has a unique id, two classes, a data-category attribute, is keyboard-focusable, and has its language explicitly marked in case it contains a different-language quote.

<div id="card-7" class="card card--news" data-category="tech" tabindex="0"> <p>Regular English content.</p> <blockquote lang="fr">C'est la vie.</blockquote> </div>

Combine id, class, data-category, tabindex="0", and lang on a nested element for the quote.