Topic 2.7
Global Attributes
In one line
Global attributes work on every HTML element: id and class name elements, title, lang and dir describe them, hidden, tabindex and contenteditable change behaviour, and data-* stores your own data.
Think of it like this
Labels you can stick on anything in a house. A name tag with a unique name (id), colour stickers shared by many things ("all blue stickers are kitchen items": class), a note that appears when you hover (title), a "written in Hindi" label (lang), a "put away for now" sticker (hidden), and blank labels where you write anything you want to remember (data-*). Any sticker fits any object.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Attribute
- Extra information inside an element's start tag, written
name="value". - Global attribute
- An attribute that is allowed on every HTML element, like
idorclass. - id
- A unique name for one element on the page. No two elements may share it.
- class
- A name (or several, separated by spaces) shared by any number of elements, used for styling and scripting.
- Tooltip
- A small box of text that appears when you hold the mouse over something.
- Text direction
- Whether text runs left to right (English) or right to left (Arabic, Hebrew, Urdu).
- Focusable
- Able to receive keyboard focus, so it can be reached with
Tabor.focus(). - data-* attribute
- Your own attribute starting with
data-, for storing small pieces of information on an element. - camelCase
- Writing joined words with capitals for each new word, like
userId. Used fordatasetnames.
Step by step
01Name one element with id, many with class
The contact section gets a unique id so links can jump to it. Every card shares the class card so one CSS rule styles them all; the special one has a second class.
<a href="#contact">Contact us</a>
...
<div class="card">Basic</div>
<div class="card featured">Pro</div>
<section id="contact">
<h2>Contact</h2>
</section>02Describe language and direction
Mark a phrase in another language with lang. For right-to-left scripts, add dir="rtl"; for text typed by users where you can't know the language, use dir="auto".
<p>The French say <span lang="fr">bon appétit</span>.</p>
<p lang="ar" dir="rtl">مرحبا بالعالم</p>
<p dir="auto">{{ user comment goes here }}</p>03Hide and show
hidden removes an element from the page and from screen readers. Remove the attribute (in JavaScript, el.hidden = false) to show it again. Be careful with CSS that sets display, which can win over hidden.
<p id="msg" hidden>Saved!</p>04Control keyboard focus
Links, buttons and form fields are focusable already. Only add tabindex="0" to a custom element that really acts like a control, and tabindex="-1" to something you'll focus from code, like an error summary.
<div id="errors" tabindex="-1">Please fix 2 errors.</div>
<!-- later, in JavaScript: errors.focus() -->05Store data for scripts
Put data the page's JavaScript needs on the element itself. JavaScript reads it through dataset. Remember every value comes back as a string: convert numbers with Number().
<li data-price="250" data-in-stock="true">Notebook</li>
<script>
const li = document.querySelector("li");
console.log(li.dataset.price); // "250" (a string)
console.log(li.dataset.inStock); // "true" (a string, not a boolean)
</script>06Let users edit content
contenteditable turns an element into an editable area. The browser handles typing, selection, undo and paste. Saving the result is up to your JavaScript.
<div contenteditable="true">Click and type here.</div>Try it yourself
- 1
Add a product
In the first example, add a fourth
liwithclass="item"anddata-price="60". Predict the new total, then run:Total: 470. - 2
Fix the hidden bug
In the second example, add this CSS rule:
[hidden] { display: none !important; }. Predict the second console line, then run. The red paragraph disappears and it printsnone. Many CSS resets include this rule for that reason. - 3
Walk the tab order
In the third example, click the preview's empty space, then press
Tabrepeatedly. Addtabindex="0"to the plain div and try again: it joins the order.
Code & diagrams
CSS styled the out-of-stock pencil from its data attribute. dataset turned data-in-stock into inStock.
Preview
Console
Nothing logged yet.Expected console output
Items with class item: 3
DOMStringMap { price: '120', inStock: 'true' }
string 120
Total: 410
Classes of pencil: 2 item saleThe red paragraph has hidden, but the CSS display: block beat the browser's default hidden style. A classic bug.
Preview
Console
Nothing logged yet.Expected console output
msg hidden: true none
forced hidden: true block
Direction of the Arabic line: rtl
Editable: trueClick the preview and press Tab: focus visits the button and the tabindex=0 div only. The plain div can't take focus at all.
Preview
Console
Nothing logged yet.Expected console output
button: tabIndex 0
plain: tabIndex -1
zero: tabIndex 0
minus: tabIndex -1
Focused now: minus
After focusing the plain div: minusBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Reuse an id
Give two elements id="pen" in the first example.
Break #2
Treat a data value as a number
In the first example, replace Number(li.dataset.price) with li.dataset.price.
Break #3
Use positive tabindex
Add tabindex="1" to an element near the bottom of a page.
Myth vs fact
Myth
id and class are the same, just used differently by CSS.
Fact
An id must be unique and is used for links, labels and ARIA references; a class is meant to be shared. They also have very different CSS specificity (CSS course).
Myth
hidden always hides an element.
Fact
It hides it through default CSS, which your own display rule can override. Add [hidden] { display: none !important; } if your CSS sets display on things that might be hidden.
Myth
title is a good place for helpful information.
Fact
Tooltips only appear on mouse hover. Touch, keyboard and many screen-reader users never get them, so put important information in visible text.
Myth
data-* values can be numbers or booleans.
Fact
Attribute values are always strings. data-count="3" reads as "3"; convert it yourself.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
An element with an
idalso becomes a property ofwindow("named access"):<p id="msg">is reachable aswindow.msgunless a real global with that name exists. It's handy in quick demos but fragile in real code; usegetElementById. - ▸
datasetconverts names by rule:data-user-id→userId, and settingel.dataset.lastSeen = "x"createsdata-last-seen. Names must not contain uppercase ASCII letters in HTML (they're lowercased anyway). - ▸
dir="auto"picks the direction from the first strong directional character (the first letter that belongs to a left-to-right or right-to-left script). For user-generated content, also consider thebdielement, which isolates a piece of text so it can't flip the surrounding line. - ▸
inert(Baseline 2023) makes a whole subtree non-interactive and hidden from assistive tech, which is what modal dialogs do to the page behind them.contenteditable="plaintext-only"reached all major engines in 2025; check support for older browsers.
Remember this
- 1
An attribute is extra information written inside an element's start tag, like
hrefona. Most attributes belong to particular elements, but global attributes are allowed on every element. You'll use them on nearly every page you write. - 2
**
id** gives an element a unique name: no two elements on a page may share an id. It's used by link fragments (href="#contact", Topic 1.6), bylabel for(Phase 4), byaria-labelledby,popovertargetand JavaScript'sgetElementById. Ids are case-sensitive and must not contain spaces. **class** is a space-separated list of names shared by any number of elements, mainly for CSS and JavaScript:class="card featured"has two classes. - 3
**
titleshows a tooltip on mouse hover. Don't put important information only there: touch-screen and keyboard users never see it, and screen readers read it inconsistently.lang** sets the language of an element's content (overriding the page'slang), so a French quote on an English page is pronounced and hyphenated correctly. **dir** sets the text direction:ltr(left to right),rtl(right to left, for Arabic, Hebrew, Urdu) orauto(let the browser decide from the text, useful for user-written content). - 4
**
hidden** hides an element completely: not shown, not read by screen readers, not focusable. It works through the browser's default CSS (display: none), so a CSS rule likedisplay: blockon the same element can override it and accidentally show it again. **tabindex** controls keyboard focus:0makes a non-focusable element focusable in the normalTaborder,-1makes it focusable only from JavaScript (el.focus()), and positive numbers (1,2…) force a custom order, which is almost always a mistake. - 5
**
contenteditable** makes an element's content editable by the user, like a mini word processor (true,false, orplaintext-onlyfor text without formatting). It's how rich text editors are built. **data-*** attributes store your own information on an element:data-price="250",data-user-id="7". They don't change anything on the page; JavaScript reads them throughelement.dataset(with the name converted to camelCase:data-user-idbecomesdataset.userId) and CSS can select them ([data-status="done"]). Values are always strings. - 6
Other global attributes you'll meet later:
style(inline CSS, in the CSS course),aria-*androle(accessibility, Phase 7),inert(makes a region unusable while e.g. a panel is open),draggable,spellcheck,translate="no"(tells translators to leave a brand name alone),autofocus,popover(Topic 2.6),accesskeyandinputmode/enterkeyhint(Phase 4).
Explain it without notes
What's the difference between id and class? When would you use each?
What are data-* attributes for, and how do JavaScript and CSS read them?
Explain the three kinds of tabindex values and which one to avoid.
Why can an element with hidden still be visible?
Practice
Write a list of three books, each with data-year. Add a script that logs the oldest year.
Mark up an English page sentence that contains the Hindi word नमस्ते, and a user comment of unknown language.
Make a "Saved!" message that starts hidden, and a script that shows it.
Trade-offs
- ↔
data-*attributes keep data close to the element that uses it, but large or sensitive data doesn't belong in the HTML: it's public to anyone who views the source, and big values bloat the page. - ↔
contenteditablegives editing for free, but its output HTML differs between browsers and can contain unexpected markup; real editors sanitise and normalise it, and anything users type must be treated as untrusted before you store or display it.
Done when you can
I can use
idfor unique names andclassfor shared ones.I can set
langanddiron part of a page.I can hide content with
hiddenand know the CSS trap.I can use
tabindex0 and -1 correctly and avoid positive values.I can store data in
data-*and read it withdataset, converting types.