Accessibility pattern · Layout and structure

Landmarks

Landmarks are a page's big areas: header, navigation, main content, search, footer. Screen reader users jump between them the way sighted people glance at a layout. Native elements give each area its role, and a name tells two of a kind apart.

WCAG criteria
6
Keyboard rules
4
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

Landmarks

0 found

    Built from the shop's markup, like a screen reader's landmarks list. Choose one to move focus there.

    Monsoon edit

    Glazes in rain-washed blues and earth reds, thrown by hand in Khurja.

    Caring for terracotta

    Soak a new planter for an hour before potting, so the clay does not pull water from the soil.

    Kiln notes

    One letter a month: new glazes and studio days.

    The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

    Keyboard

    Keys it answers to

    Every action works without a pointer.

    KeyWhat it does
    TabMoves to Show structure, then through the landmarks list, then into the shop.
    Enter or SpaceOn an entry in the landmarks list, moves focus to that landmark; the next Tab carries on inside it.
    SpaceOn Show structure, outlines and names every landmark in the shop, and marks the section that is not one.
    D or RScreen reader keys, not the page's: D in NVDA and R in JAWS move to the next landmark. The markup is all they need.

    Screen readers

    What it announces

    Written from the roles, names and states in the markup.

    WhenExpected announcement
    Enter on Navigation, Categories in the listCategories, navigation landmark
    Enter on the shop's content regionMonsoon edit, region
    A screen reader lists the landmarksShop header region, Shop search search, Categories navigation, Monsoon edit region, Visit the studio complementary, Shop footer region, Kiln notes form, Customer help navigation
    Show structure is switched onShow structure, switch, on (checked)
    With the names removed, the list reaches a navigationNavigation landmark, with nothing to tell it from the other one

    These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

    Code

    Copy the code

    The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

    The markup

    <div class="ap-landmarks" data-ap-landmarks>
      <div class="ap-landmarks__rotor">
        <button type="button" class="ap-landmarks__switch" role="switch" aria-checked="false" data-lm-structure>
          <span class="ap-landmarks__track" aria-hidden="true"><span class="ap-landmarks__knob"></span></span>
          Show structure
        </button>
        <div class="ap-landmarks__rotor-top">
          <p class="ap-landmarks__rotor-name" id="lm-rotor-name">Landmarks</p>
          <p class="ap-landmarks__count"><span data-lm-count>0</span> <span>found</span></p>
        </div>
        <ol class="ap-landmarks__list" role="list" aria-labelledby="lm-rotor-name" data-lm-list></ol>
        <p class="ap-landmarks__warn" data-lm-warn hidden>Landmarks of the same kind need different names, or they all sound the same.</p>
        <p class="ap-landmarks__note">Built from the shop's markup, like a screen reader's landmarks list. Choose one to move focus there.</p>
      </div>
    
      <div class="ap-landmarks__page" data-lm-page>
        <!-- On a real page this is <header>, a child of <body>: the banner landmark.
             This shop sits inside this page's own <main>, so it is a named region. -->
        <section class="ap-landmarks__top" aria-label="Shop header" data-lm-real="banner">
          <a class="ap-landmarks__logo" href="#lm-home">
            <svg class="ap-landmarks__mark" viewBox="0 0 32 32" aria-hidden="true" focusable="false"><path d="M11 4.5h10M12.5 4.5v3.2C8.6 9.6 6.5 13 6.5 17c0 5.6 4.2 10 9.5 10s9.5-4.4 9.5-10c0-4-2.1-7.4-6-9.3V4.5"/><path d="M7.2 14.5h17.6M7 19.5h18"/></svg>
            <span>Mitti</span>
          </a>
          <search class="ap-landmarks__search" aria-label="Shop search">
            <form class="ap-landmarks__find" action="#lm-results">
              <label class="ap-landmarks__vh" for="lm-q">Search the shop</label>
              <svg class="ap-landmarks__glass" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.5"/><path d="m16 16 4 4"/></svg>
              <input class="ap-landmarks__input" id="lm-q" name="q" type="search" placeholder="Search" enterkeyhint="search" autocomplete="off" />
            </form>
          </search>
          <nav class="ap-landmarks__nav" aria-label="Categories">
            <ul class="ap-landmarks__menu" role="list">
              <li><a href="#lm-planters">Planters</a></li>
              <li><a href="#lm-mugs">Mugs</a></li>
              <li><a href="#lm-bowls">Bowls</a></li>
              <li><a href="#lm-lamps">Lamps</a></li>
            </ul>
          </nav>
        </section>
    
        <div class="ap-landmarks__body">
          <!-- On a real page: <main>. One per page. -->
          <section class="ap-landmarks__content" aria-labelledby="lm-content-name" data-lm-real="main">
            <h3 class="ap-landmarks__name" id="lm-content-name">Monsoon edit</h3>
            <p class="ap-landmarks__lead">Glazes in rain-washed blues and earth reds, thrown by hand in Khurja.</p>
            <ul class="ap-landmarks__products" role="list">
              <li class="ap-landmarks__product">
                <span class="ap-landmarks__swatch ap-landmarks__swatch--clay" aria-hidden="true"></span>
                <a href="#lm-planter">Terracotta herb planter</a>
                <span class="ap-landmarks__price">₹649</span>
              </li>
              <li class="ap-landmarks__product">
                <span class="ap-landmarks__swatch ap-landmarks__swatch--blue" aria-hidden="true"></span>
                <a href="#lm-mug">Blue pottery mug</a>
                <span class="ap-landmarks__price">₹420</span>
              </li>
              <li class="ap-landmarks__product">
                <span class="ap-landmarks__swatch ap-landmarks__swatch--cream" aria-hidden="true"></span>
                <a href="#lm-bowl">Khurja serving bowl</a>
                <span class="ap-landmarks__price">₹1,150</span>
              </li>
            </ul>
            <!-- No name, so not a landmark: just a section of the content. -->
            <section class="ap-landmarks__care">
              <h4>Caring for terracotta</h4>
              <p>Soak a new planter for an hour before potting, so the clay does not pull water from the soil.</p>
            </section>
          </section>
    
          <aside class="ap-landmarks__aside" aria-labelledby="lm-aside-name">
            <h3 class="ap-landmarks__name" id="lm-aside-name">Visit the studio</h3>
            <p>Watch the potters at the wheel, Tuesday to Sunday, 10 am to 6 pm.</p>
            <a href="#lm-visit">Plan a visit</a>
          </aside>
        </div>
    
        <!-- On a real page this is <footer>, a child of <body>: the content info landmark. -->
        <section class="ap-landmarks__foot" aria-label="Shop footer" data-lm-real="contentinfo">
          <form class="ap-landmarks__news" aria-labelledby="lm-news-name" action="#lm-subscribed">
            <h3 class="ap-landmarks__name" id="lm-news-name">Kiln notes</h3>
            <p class="ap-landmarks__small">One letter a month: new glazes and studio days.</p>
            <label class="ap-label" for="lm-email">Email address</label>
            <div class="ap-landmarks__row">
              <input class="ap-input" id="lm-email" name="email" type="email" autocomplete="email" required />
              <button type="submit" class="ap-btn ap-btn--primary">Subscribe</button>
            </div>
            <p class="ap-landmarks__done" role="status"></p>
          </form>
          <nav class="ap-landmarks__help" aria-label="Customer help">
            <ul role="list">
              <li><a href="#lm-delivery">Delivery</a></li>
              <li><a href="#lm-returns">Returns</a></li>
              <li><a href="#lm-contact">Contact us</a></li>
            </ul>
          </nav>
          <p class="ap-landmarks__legal">© 2026 Mitti Studio, Khurja</p>
        </section>
      </div>
    </div>
    

    WCAG 2.2

    What it meets

    The success criteria this pattern takes care of, and how.

    • 1.3.1 Info and Relationships Level A

      The page's areas are exposed as landmarks by nav, aside, search and named sections and forms, not only drawn with borders and backgrounds.

    • 2.4.1 Bypass Blocks Level A

      Screen reader users skip the header and menus by moving to the next landmark, a technique WCAG lists for bypassing blocks.

    • 2.4.3 Focus Order Level A

      Choosing a landmark from the list moves focus into it, so the next Tab continues from there and not from the top.

    • 2.4.6 Headings and Labels Level AA

      Each landmark's name says what it holds (Categories, Customer help), so two navigations are told apart without opening them.

    • 2.4.7 Focus Visible Level AA

      A landmark that receives focus from the list shows a two-pixel ring, so sighted keyboard users see where they landed.

    • 4.1.2 Name, Role, Value Level A

      Show structure is a button with role=switch and aria-checked, so its name, role and on or off state are exposed.

    Usage

    When to use it

    Use it

    • Every page: a header, one main, a footer, and a navigation landmark for each menu.
    • Search, sidebars and forms people come back to, like a newsletter sign-up or a filter panel.

    Use something else

    • Naming every card and panel: a list of twenty regions is as unhelpful as none.
    • Landmarks instead of headings: landmarks mark the big areas, headings the topics inside them.
    • Landmark roles on small widgets such as a single button group or a card.

    Common failures

    How it usually goes wrong

    • Two main landmarks

      A page with two mains leaves people guessing where the content starts. Use one; if a single-page app swaps views, swap what is inside it.

    • Navigations that all sound the same

      Three unnamed navs are read as navigation, navigation, navigation. Name each one with aria-label: Categories, Customer help, Breadcrumb.

    • Names that repeat the role

      aria-label="Main navigation" is read as main navigation navigation. The role is announced anyway, so name the purpose only.

    • A section expected to be a region

      A section with no name is not a landmark at all. Point aria-labelledby at its heading if people need to jump to it, or leave it a plain section.

    • Content outside every landmark

      Text that sits outside all landmarks is skipped by landmark navigation. On a real page, everything belongs to the header, main, footer or another landmark.

    • Header and footer nested too deep

      A header or footer inside an article, aside or section is not the page's banner or content info. Keep the site-wide ones as direct children of body.

    Notes

    Building it

    • On a real page, the site-wide header and footer are header and footer elements that are children of body, which makes them the banner and content info landmarks, and the content goes in main. This shop sits inside this page's own main, so those three are named sections here, and the list marks what each would be.
    • nav, aside and search are always landmarks. A section or a form becomes one only when it has a name, from aria-labelledby or aria-label.
    • Landmark names must be unique on the page. This page already has a Breadcrumb navigation and an inspector aside, which is why the shop's landmarks have names of their own.
    • The search element is supported in current browsers; for older ones, role="search" on a div or form does the same job.
    • The landmarks list is built from the markup the way a screen reader builds its own. The option above removes every name: the regions and the form drop out, and the two navigations become indistinguishable.

    Sources: WAI-ARIA Authoring Practices: Landmark regions · WCAG technique ARIA11: landmarks to identify regions · HTML: the search element

    Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction