HTML Main Element
When you open a newspaper, your eyes skip the masthead, the adverts, and the page numbers, and land on the story. You know which part is "the thing I came for." On the web, the <main> element tells browsers and assistive tools exactly the same thing: this is the real content of the page.
It is one of the simplest elements to use, and one of the most useful. A single <main> helps screen reader users jump past your logo and menu in one keystroke, helps reader modes find the article, and gives skip links a place to land.
What You Will Learn
- What
<main>means, and what belongs inside it - Why a page has only one visible
<main> - What stays outside it: headers, menus, sidebars, and footers
- How
<main>works with skip links - How to handle
<main>in single-page apps - Layout CSS for the content area
- Accessibility, security, and global notes
- Common mistakes
The Basics
- HTML Code
- Browser Output
<body>
<header>…site name and menu…</header>
<main id="main" tabindex="-1">
<h1>How to bake bread</h1>
<p>Mix flour, water, salt, and yeast…</p>
<h2>Shaping the loaf</h2>
<p>Start with a round of dough…</p>
</main>
<footer>…copyright and links…</footer>
</body>
main {
max-width: 70ch;
margin-inline: auto;
padding: 1.5rem 1rem;
}
How to bake bread
Mix flour, water, salt, and yeast…
Shaping the loaf
Start with a round of dough…
<main> has no visual style of its own. It is a plain block. Its job is meaning: a screen reader announces it as the main landmark, and offers a shortcut to jump straight to it.
The Golden Rule: One Visible <main>
A page has one dominant content area, so it has one visible <main>. If there were several, a screen reader user could not tell which is the "real" one, and the shortcut would stop meaning anything.
Try adding extra <main> elements below, and count what a screen reader would find:
- HTML Code
- Browser Output
<!-- Correct: exactly one visible main -->
<main>…</main>
<!-- Wrong: two visible mains -->
<main>…programme…</main>
<main>…special offers…</main>
<!-- Allowed: an extra main that is hidden -->
<main>…programme…</main>
<main hidden>…another view that is not showing yet…</main>
const all = document.querySelectorAll("main").length;
const visible = document.querySelectorAll("main:not([hidden])").length;
console.log(all + " in the HTML, " + visible + " visible");
// A correct page always has exactly one visible
The specification allows several <main> elements only if all but one have the hidden attribute. That is useful for sites that swap "views" in the same document. For an ordinary page, just use one.
role="main"Older pages wrote <div role="main">. A real <main> has the same meaning built in, so you do not need to add role="main" to it.
What Belongs Inside <main>
The content that is unique to this page: the thing the visitor came for.
Inside <main> | Outside <main> |
|---|---|
The page's <h1> and the article or product | The site logo and name (in the page <header>) |
| Sections, articles, forms, tables, and images for this page | The site-wide menu (in <nav>) |
| A search form for this page's results | A site-wide search box (in the header) |
| A "related products" box that belongs with this content | A page-wide sidebar (in <aside> outside main) |
| Pagination for this list | Copyright and legal links (in <footer>) |
| An embedded video, chart, or tool | Cookie banners and chat widgets (usually outside) |
A handy test: would this block be repeated, unchanged, on many other pages? If yes, it probably does not belong in <main>.
Where <main> Can and Cannot Sit
- Allowed: directly in
<body>, or inside plain wrappers such as a<div>. - Not allowed: inside
<article>,<aside>,<header>,<footer>, or<nav>.
A typical modern page is built like this:
<body>
<a class="skip-link" href="#main">Skip to main content</a>
<header>…</header>
<div class="layout">
<nav aria-label="Section">…</nav>
<main id="main" tabindex="-1">
<h1>Page title</h1>
…
</main>
<aside aria-label="Related">…</aside>
</div>
<footer>…</footer>
</body>
Here the section menu and the sidebar sit beside <main>, not inside it, because they are not the page's own content.
Try It: What Reader Mode Keeps
Reader modes (in browsers and apps), and some "read aloud" tools, try to strip a page down to the content that matters. A correct <main> helps them. Tick the box to see which parts of this page a reader mode would keep.
- HTML Code
- Browser Output
<header>Site header and logo</header>
<nav aria-label="Main">Home · Programme · Tickets · Contact</nav>
<main>
<h1>How to bake bread</h1>
<p>Mix flour, water, salt, and yeast. Knead until smooth…</p>
</main>
<aside>Related: sourdough, cookies</aside>
<footer>© 2026 My Site · Privacy · Terms</footer>
How to bake bread
Mix flour, water, salt, and yeast. Knead until smooth, rest until doubled, then shape and bake.
Reader tools use many clues (they are not required to follow <main>), but a clear <main>, a good <h1>, and an <article> make their job much easier.
Skip Links and the tabindex="-1" Trick
A skip link jumps keyboard users past the menu, straight to the content. <main> is the natural target:
<a class="skip-link" href="#main">Skip to main content</a>
…
<main id="main" tabindex="-1">…</main>
id="main"gives the link something to point at.tabindex="-1"lets the element receive focus from a script or a link, without adding it to the normal Tab order. Without it, some browsers scroll to<main>but leave the keyboard focus behind in the header.- Because
<main>is not interactive, you may want to hide its focus outline:main:focus { outline: none; }. This is acceptable here because the user did not "tab into" it, but never remove outlines from buttons, links, or fields.
See Header for the full skip link pattern.
Single-Page Apps and Changing Views
In a single-page app (React, Vue, and others), "navigating" does not load a new page. The content swaps, and a screen reader hears nothing. After each view change, help people notice:
function showView(title) {
document.title = title + " · My Site"; // 1. update the tab title
const main = document.getElementById("main");
main.focus(); // 2. move focus to the new content
}
Good habits:
- Keep one persistent
<main>and replace what is inside it, or hide the old one withhidden. - Update
document.titlefor every view. - Move focus to
<main>or to the new<h1>(withtabindex="-1"), or announce the change in a polite live region. - Restore the scroll position sensibly, and keep the Back button working.
Layout CSS
<main> is a good hook for the layout of your content area:
body {
min-height: 100vh;
display: grid;
grid-template-rows: auto 1fr auto; /* header, main, footer */
}
main {
max-width: 70ch; /* a comfortable line length */
width: 100%;
margin-inline: auto;
padding: 1.5rem 1rem;
}
The 1fr row makes <main> stretch, so the footer stays at the bottom even on a short page.
Accessibility at a Glance
- Exactly one visible
<main>per page, with norole="main"needed. - Put the page's unique content inside it, and repeated blocks (logo, site menu, footer) outside.
- Provide a skip link that targets it, with
idandtabindex="-1". - Start the content with an
<h1>(inside<main>or just before it), and keep heading levels in order. - Do not put
<main>inside<article>,<aside>,<header>,<footer>, or<nav>. - In a single-page app, update the title and move focus after a view change.
- Do not hide the real content with
hiddenordisplay: nonewhile visitors expect to read it. - Keep a readable line length (about 60 to 80 characters), and allow zooming to 200% or more.
Security and Privacy Notes
<main>protects nothing. It is structure. Never rely on hiding content in a second<main>withhidden, because it is still in the HTML source for anyone to read.- Escape user-supplied content you place inside
<main>, such as comments and profile text. - Do not put private data (personal details, tokens, account numbers) into the page source "for later use." It can be read by any script or extension.
- Be careful with user-generated HTML. If you allow rich text, clean it with a trusted sanitiser, so it cannot add a second
<main>, scripts, or misleading structure.
Global Audience Notes
- Set
langon<html>, and on passages in another language inside<main>. - Right-to-left pages (
dir="rtl") work with<main>unchanged. Prefer logical properties likemargin-inlineandpadding-inlinein your layout. - Line length differs by script. The
chunit suits Latin text. For Chinese, Japanese, and Korean, a width inemunits (about 30 to 40 characters per line) often reads better. - Keep the order of the HTML the same as the reading order, so translation tools, voice assistants, and screen readers hear it properly.
- Give the page one clear
<h1>in the page's language, which also becomes the title people hear in search results and readers. - Light pages (few scripts, small images) work better on slow or older devices, which many visitors worldwide rely on.
Common Mistakes to Avoid
- More than one visible
<main>. - Putting the site header, menu, or footer inside
<main>. - Putting
<main>inside<article>,<aside>,<header>,<footer>, or<nav>. - Wrapping the whole
<body>in<main>. - Adding
role="main"to a<main>(redundant), or to several divs. - No skip link, or a skip link whose target does not exist.
- Forgetting
tabindex="-1"so focus does not really move. - Using
<main>as a layout wrapper for several unrelated areas. - Hiding the real content with
hiddenordisplay: noneby mistake. - Changing views in a single-page app without updating the title or focus.
- Skipping the
<h1>, or using several<h1>elements without a reason. - Using
<main>for every page "section." Use<section>and<article>for that.
Practice Time
Try these in your editor:
- Build a page with a
<header>, a<main>, and a<footer>. - Add an
<h1>inside<main>, and a few<h2>sections. - Use
querySelectorAll("main")in the console to count your<main>elements. - Add a skip link that targets
<main id="main" tabindex="-1">, and test it with Tab and Enter. - Move a site-wide sidebar out of
<main>, and explain why. - Style
<main>with a maximum width and centered margins. - Use CSS grid on
<body>so the footer sits at the bottom of a short page. - Make a page with two views, and hide the inactive one's
<main>withhidden. - Write a small
showView()function that updatesdocument.titleand moves focus. - Bonus: use your browser's accessibility panel (or a screen reader's landmark list) to confirm there is exactly one
main.
Quick Recap
Click a question to check your answer.
1. What is the <main> element for?
It marks the dominant, unique content of the page, the thing the visitor came for. It is announced as the main landmark, and gives screen reader users a shortcut past the repeated header and menu.
2. How many <main> elements may a page have?
Only one visible at a time. Extra <main> elements are allowed only if they have the hidden attribute.
3. What should stay outside <main>?
Blocks repeated across pages: the site header and logo, the site-wide menu, page-wide sidebars, and the footer. <main> also cannot sit inside <article>, <aside>, <header>, <footer>, or <nav>.
4. Do you need role="main" on <main>?
No. The element already has the main role built in.
5. Why add tabindex="-1" to <main>?
So that a skip link or a script can move keyboard focus to it, without adding it to the normal Tab order. Otherwise some browsers scroll there but leave focus behind.
6. What should a single-page app do when the view changes?
Update document.title, and move focus to <main> (or the new <h1>), or announce the change, because screen readers get no page-load signal.
Key Takeaways
<main>marks the page's unique, dominant content and is announced as the main landmark.- Use one visible
<main>per page. Extra ones must behidden. - Keep repeated blocks (header, site menu, footer, page-wide sidebars) outside it, and never put
<main>inside<article>,<aside>,<header>,<footer>, or<nav>. - You do not need
role="main". - Make it the target of a skip link, with an
idandtabindex="-1". - In single-page apps, update the title and move focus after view changes.
- Good structure helps reader modes, screen readers, and translation tools, but it is not security.
- Use
<section>and<article>for subdivisions inside it, not more<main>elements.
Next, learn how to group content into themed parts, in Section, or return to the Semantic HTML overview.