HTML Attributes In Depth: Global Attributes You Should Know
Go beyond href and src: learn HTML's global attributes — id, class, style, title, lang, data-*, hidden, tabindex — and why inline style is a last resort.
What you will learn
You already know that an attribute is extra information written inside an opening tag, like href="..." on a link or src="..." on an image. Those are specific to one element — href only makes sense on <a>, src only on <img> and a few others. But HTML also has a set of global attributes: ones that work on almost every element, regardless of what it is. In this lesson you will learn the most useful global attributes, why the style attribute you have been using is actually the one to use least, and how to attach your own custom data to any element.
A quick recap: what makes an attribute
An attribute is a name="value" pair written inside the opening tag, separated by spaces, with the value in quotes:
<p id="intro" class="highlight" title="A friendly welcome">Hello!</p>
Here id, class and title are three separate attributes on the same <p>. (If any of this feels new, the elements-and-tags lesson covers the basic anatomy of tags and attributes in detail — this lesson builds on that and focuses on the attributes themselves.)
Two kinds of attributes
| Kind | Works on | Examples |
|---|---|---|
| Element-specific | Only certain elements | href (<a>), src/alt (<img>), type (<input>) |
| Global | Almost any HTML element | id, class, style, title, lang, data-*, hidden, tabindex |
This lesson is about the second kind — the attributes that are always available, no matter which element you’re writing.
id: a unique name for one element
<p id="welcome-message">Welcome to the site!</p>
- Must be unique on the whole page — never reuse the same
idtwice. - Used to target one exact element from CSS (
#welcome-message), from JavaScript, or as the destination of a same-page link (<a href="#welcome-message">, which you met in the links lesson). - No spaces allowed, and by convention it is written in lower case with hyphens:
main-nav, notMain Nav.
class: a reusable label
<p class="card">First card</p>
<p class="card">Second card</p>
<p class="card highlighted">Third card, also highlighted</p>
- Can be used on as many elements as you like.
- One element can have multiple classes, separated by spaces — the third paragraph above has both
cardandhighlighted. - Used constantly in CSS (
.card { ... }) and JavaScript, to style or select a whole group of elements at once.
You met id and class already in the grouping lesson; they are worth repeating here because they are the two most-used global attributes of all.
style: inline CSS (use sparingly)
<p style="color: red; font-weight: bold;">Important notice</p>
style lets you write CSS directly on one element. It is useful for quick experiments, but on a real project it is usually the wrong tool, for three reasons:
- It cannot be reused. If ten paragraphs need the same red, bold style, you must repeat the same
styletext ten times. - It is hard to maintain. Changing the look later means hunting through your HTML file for every
style=""instead of editing one CSS rule. - It always wins, even over CSS you write carefully in a stylesheet, which can cause confusing bugs (you will learn why in the CSS specificity lesson).
The better habit, almost always:
<!-- Instead of this -->
<p style="color: red; font-weight: bold;">Important notice</p>
<!-- Do this -->
<p class="notice">Important notice</p>
.notice {
color: red;
font-weight: bold;
}
Keep style for quick testing in the editor, or for a value that is genuinely different on every single element (like a dynamically calculated width set by JavaScript).
title: a tooltip
<p title="This paragraph explains the title attribute.">Hover over me.</p>
<abbr title="Hypertext Markup Language">HTML</abbr>
Hovering over the element shows the title text as a small tooltip. It is handy for a short explanation of an abbreviation, or an extra hint — but do not rely on it for anything important, since it is invisible on touchscreens (there’s no “hover” on a phone) and easy for a visitor to miss entirely.
lang: declaring the language
You’ve already seen this one on every page you’ve written, on the <html> tag:
<html lang="en">
lang tells browsers, search engines and screen readers what language the content is written in. A screen reader uses it to choose the correct pronunciation rules — English rules would badly mispronounce Hindi or French text. You can also set it on a smaller piece of content that switches language:
<p>My favourite word in French is <span lang="fr">bonjour</span>.</p>
Always set lang on <html>. It is a one-line habit with a real accessibility benefit.
hidden: hide an element completely
<p hidden>You will not see this at all.</p>
hidden is a boolean attribute (you met these in the elements-and-tags lesson — its presence alone turns it on, it needs no value). An element with hidden is removed from the page exactly like CSS display: none — it takes up no space and is skipped by screen readers. It is most useful for content that JavaScript will reveal later, such as a message that only appears after a form is submitted.
tabindex: keyboard navigation order
Pressing the Tab key on a keyboard moves focus between interactive elements (links, buttons, inputs) in the order they appear in the HTML. tabindex lets you adjust that:
<input type="text" tabindex="1">
<input type="text" tabindex="2">
<button tabindex="0">Submit</button>
| Value | Meaning |
|---|---|
tabindex="0" |
Include this element in the natural tab order (useful to make a non-interactive element, like a <div>, keyboard-focusable) |
tabindex="-1" |
Remove this element from the tab order, but it can still be focused by JavaScript |
tabindex="1", "2", … |
A custom, explicit order |
Be careful with positive numbers. They override the natural reading order of your page, and if you forget to number every focusable element, keyboard navigation can jump around unpredictably. Prefer writing your HTML in the order you want people to tab through, and reach for tabindex="0" or "-1" only when needed.
contenteditable: let visitors edit text in place
<p contenteditable="true">Click me and start typing!</p>
Turns any element into an editable text box, right there on the page. It is what powers rich-text editors and simple “click to edit” interfaces on real sites (usually combined with JavaScript to save the changes).
draggable: enable drag-and-drop
<p draggable="true">Drag me around</p>
Marks an element as draggable. By itself it doesn’t do much — you pair it with JavaScript’s Drag and Drop API to actually respond to the drag — but the attribute is what makes an element eligible in the first place.
data-*: your own custom attributes
Sometimes you want to attach information to an element that has no built-in attribute for it — information meant purely for your own JavaScript to read later. HTML lets you invent any attribute you like, as long as it starts with data-:
<p data-user-id="482" data-role="admin" data-signed-up="2026-01-15">
Priya Sharma
</p>
<button data-product-id="A104" data-price="799">Add to Cart</button>
These attributes do nothing visible by themselves. They exist so JavaScript can read them later, for example when the “Add to Cart” button is clicked:
const button = document.querySelector("button");
console.log(button.dataset.productId); // "A104"
console.log(button.dataset.price); // "799"
Notice the naming pattern: data-product-id in HTML becomes dataset.productId in JavaScript (hyphens turn into camelCase). You will use data-* attributes constantly once you reach the JavaScript and DOM lessons — they are the standard way to link a piece of HTML to information your script needs, without inventing a non-standard attribute that could clash with a future version of HTML.
The full list of global attributes (for reference)
You do not need to memorise all of these. The ones above are what you will actually reach for as a beginner. Here is the rest, so you recognise them if you see them:
| Attribute | What it does |
|---|---|
accesskey |
Assigns a keyboard shortcut to jump to the element |
dir |
Text direction: ltr (left-to-right) or rtl (right-to-left, for languages like Arabic and Urdu) |
spellcheck |
Turns the browser’s spell-checker on or off for editable content |
translate |
Hints to browser translation tools whether this content should be translated |
contextmenu |
Associates a custom right-click menu (rarely supported today) |
Attribute rules, revisited
A few rules from the elements-and-tags lesson are worth restating here, because they apply to every attribute in this lesson too:
-
Attributes go only in the opening tag.
-
Separate multiple attributes with spaces, and the order does not matter:
<p id="a" class="b" title="c">...</p> <p title="c" class="b" id="a">...</p> <!-- identical meaning --> -
Always wrap the value in quotes.
-
Boolean attributes (
hidden,disabled,required,checked) need no value — just writing the name turns them on.
Common mistakes
- Reusing an
idon more than one element. CSS, JavaScript and same-page links can all behave unpredictably when anidis not unique. - Reaching for
style=""by default. It works, but it does not scale — use aclassand a stylesheet for anything you will reuse or need to maintain. - Skipping
langon<html>. A one-line fix that genuinely helps screen reader users and search engines. - Using large positive
tabindexvalues everywhere. It is easy to create a confusing tab order. Let the natural HTML order do the work whenever possible. - Inventing a custom attribute without the
data-prefix, such as<div info="482">. Browsers may not recognise it correctly, and it can clash with a future official HTML attribute. Always prefix custom attributes withdata-. - Forgetting that
data-*values are always strings.data-price="799"gives you the text"799"in JavaScript, not the number799— you will need to convert it (Number(...)) before doing maths with it.
Interview-style questions
What is a global attribute?
An attribute that can be used on almost any HTML element, regardless of its type — such as id, class, style, title, lang and data-*, as opposed to element-specific attributes like href or src.
Why is the style attribute generally discouraged over a CSS class?
It cannot be reused across elements, it is harder to maintain since styles are scattered through the HTML, and it overrides stylesheet rules, which can cause confusing specificity issues.
What is a data-* attribute used for?
To attach custom information to an element for your own JavaScript to read, when no built-in HTML attribute fits — for example data-product-id on a button.
What does tabindex="0" do?
It adds the element to the natural keyboard tab order without changing that order, which is often used to make a non-interactive element (like a styled <div>) keyboard-focusable.
Practice
-
Use the Practice in Editor button. Add a
titleattribute to the second paragraph and hover over it to see the tooltip. -
Add a
data-priceattribute to the editable paragraph, then imagine (or write, if you know a little JavaScript) how you would read it withelement.dataset.price. -
Rewrite this paragraph so it no longer uses
style, using a class and CSS instead:<p style="background: yellow; padding: 10px; border-radius: 6px;"> Special offer! </p> -
Find one real website, right-click any element, choose Inspect, and look for at least one
data-*attribute in its HTML. Note what you think it might be used for.
Recap
- Global attributes (
id,class,style,title,lang,data-*,hidden,tabindex,contenteditable,draggable) work on almost any element; element-specific attributes (href,src) only work on certain ones. idnames one unique element;classlabels a reusable group.stylewrites CSS directly on an element — prefer aclassand a stylesheet whenever the style will repeat or needs maintaining.langon<html>helps screen readers and search engines;hiddenremoves an element completely.tabindexadjusts keyboard tab order — use0and-1more than large custom numbers.data-*attributes let you attach your own custom information to any element for JavaScript to read later.