Build Accessible Breadcrumbs in Webflow (Manual + Auto)

Intermediate 32:04 webflowbreadcrumbsaccessibilitynavigationcomponents

Build two reusable, accessible breadcrumb systems in Webflow — a manual component you configure by hand and an automatic one that reads the URL for you.

Key takeaways

  • Breadcrumbs belong in an ordered list, not an unordered one — the order is meaningful (home first, current page last), and an <ol> communicates that to both screen readers and search engines.
  • Accessibility lives in a handful of attributes: aria-label on the nav landmark, aria-current="page" on the last link, and aria-hidden on any visual separator so it isn't read aloud.
  • An intermediate crumb that points nowhere (like a CMS collection path) should never look or behave like a link — aria-disabled plus a little CSS turns it into plain, non-clickable text.
  • Building the breadcrumb as a Webflow component with properties means you control the whole trail — separators, labels, links, visibility — from one place instead of editing dozens of pages by hand.
  • The manual version gives you full control on shallow, static sites; the automatic version reads the page URL and builds itself, which is what you want for CMS and deeply nested structures.

Video chapters

  1. 00:00 Intro
  2. 01:43 Structure of the Webflow Project
  3. 04:24 Building the manual breadcrumb
  4. 11:49 Turning the manual breadcrumb into a component
  5. 16:37 Testing the manual breadcrumb
  6. 22:11 Building the automatic breadcrumb
  7. 25:37 Turning the automatic breadcrumb into a component
  8. 28:00 Testing the automatic breadcrumb
  9. 31:14 Outro

By the end of this you’ll have two reusable, accessible breadcrumb systems you can drop into any Webflow project — one manual, for full control on simple sites, and one automatic, that reads the page URL and builds the trail itself for CMS and deeply nested structures.

Breadcrumbs sound trivial until you try to make them right: an ordered list so the order actually means something, a nav landmark a screen reader can announce, separators that don’t get read aloud, and no dead links pretending to be clickable. We’ll build both versions as real Webflow components with properties, so you tweak the whole trail from one place instead of editing every page by hand.

The manual version is perfect when your structure is shallow and you want to define each step yourself. The automatic one is built for scale — it works out the labels, the links, and even which segments aren’t real pages, all on its own.

How it works

The accessible foundation is the same for both. The trail is a nav element with aria-label="breadcrumb", so screen readers announce it as the breadcrumb, not a generic nav. Inside it goes an ordered list — not unordered — because breadcrumbs are sequential: home first, current page last, and that order is information. Each item is a list item holding a link, and the last link gets aria-current="page" to mark the page you’re on. Separators are decorative, so they’re kept out of the accessibility tree: the character separator (a >) carries aria-hidden="true", the icon separator is marked as decorative so it’s skipped, and the third option is a pure-CSS separator generated with a ::after rule (a / after every item except the last) — no extra element at all. All three exist so the component can offer the choice; you switch between them with a visibility property.

The manual component puts you in control. Once the structure is built you convert it into a Webflow component and expose everything as properties, grouped by purpose: a visibility and content property for each separator, and per-level properties for the labels, the links, and each item’s visibility. That’s what makes it reusable — on a shallow static page you might show only home plus the current page and hide the levels in between; on a blog post you show more. The important accessibility detail is the dead crumb problem: a URL like /blog/posts/post-slug has a posts segment that isn’t a real page. Left as-is it looks and behaves like a broken link. The fix is aria-disabled="true" on that link (exposed as a property so you set it per level) plus a short CSS rule that removes pointer events, inherits the surrounding text color, and drops the underline — so it reads as plain text, honestly.

The automatic component does the thinking for you. It starts from a stripped-down copy of the manual one — just the home item and a template for the current level — plus a small script. On load the script reads the current URL and splits it into segments on the slashes. For every segment except the first (home) and the last (current page) it creates a list item, uses the slug as the label with dashes swapped for spaces, and then tests whether that partial path resolves to a real page: if it does, it renders a real link; if it doesn’t — like a CMS collection path — it renders plain text instead, so you never ship a broken link. The last segment is left alone if you’ve typed a custom label (handy for binding a CMS field like the post title), or filled from the URL if you left it empty. That path-testing is also why you may see a harmless 404 in the console: the script pinged a segment, found nothing, and quietly downgraded it to text.

The script finds what it needs through two small logic attributes — one that marks the breadcrumb wrapper as the component, and one that marks the last list item as the current level. These are for the code, not for accessibility, and they come pre-set in the cloneable, so you don’t have to think about them.

How to use it

  1. Clone the project. Grab the Webflow cloneable. It ships both components — breadcrumb manual and breadcrumb auto — with the accessibility attributes, the three separator styles, and the fully commented script already wired up.

  2. Build the trail (manual). A nav with aria-label="breadcrumb" wraps an ordered list; each list item holds a link. Give the last link aria-current="page". Add your separators (character with aria-hidden="true", a decorative icon, or the CSS ::after), then select the whole wrapper and convert it to a component.

  3. Expose properties. Group them cleanly — visibility + content per separator, and per level a link, a text label, and a visibility toggle. On the intermediate levels also expose an aria-disabled property (default false) for crumbs that don’t link anywhere.

  4. Configure per page (manual). Drop the component in, choose one separator (hide the other two), show only the levels you need, and set each level’s label and link. For a segment that isn’t a real page, set its aria-disabled property to true so it renders as plain text.

  5. Or go automatic. Drop in breadcrumb auto, hide the separators you don’t want, and that’s it — the script builds the rest from the URL. Only touch the last level’s text property when you want to override a long slug (or bind it to a CMS field).

  6. Publish and test on the live link. Click through: home should reach the homepage, real segments should link, non-page segments should read as plain text, and the current page should be labelled and marked. A stray 404 in the console for a non-existent segment is normal.

Configuration reference

Attribute Values Default What it does
aria-label breadcrumb Goes on the nav element that wraps the whole trail. It names the landmark so screen readers announce it as breadcrumb navigation, not just another unlabelled nav.
aria-hidden true Goes on a visual separator (the > character, or the icon). Set to true so screen readers skip the decorative symbol instead of reading it out between every item.
aria-current page Goes on the last link — the current page. It tells assistive tech which crumb is the page the visitor is actually on.
aria-disabled true / false false Goes on an intermediate crumb that links nowhere (like a CMS collection path). Set to true to mark it non-interactive; paired with a little CSS it reads as plain text instead of a dead link.

Resources

Frequently asked questions

How do I build an accessible breadcrumb in Webflow?
Wrap the trail in a nav element with an aria-label, put the items in an ordered list, give the last link aria-current="page", and hide any visual separator with aria-hidden. That gives screen readers a properly named, correctly ordered navigation they can actually use.
Should breadcrumbs use an ordered or an unordered list?
An ordered list. A breadcrumb is a sequence from the homepage down to the current page, and that order carries meaning — an <ol> communicates it correctly to assistive tech and search engines, where an unordered list would not.
How do I handle a breadcrumb segment that is not a real page?
Don't leave it as a live link to nowhere. Add aria-disabled to that item and a bit of CSS to strip its pointer events and link styling, so it reads as plain text — accurate for sighted users and screen readers alike. This is common with CMS collection paths like /blog/posts/.
Manual or automatic breadcrumbs — which one should I use?
Pick the manual component for small, shallow sites where you want to set each label and link yourself. Pick the automatic one for CMS-driven or deeply nested sites: it reads the page URL and builds the trail on its own, so you never configure anything per page.
Why does the automatic breadcrumb log a 404 in the browser console?
That's expected, not a bug. The script pings each URL segment to check whether it resolves to a real page; when a segment (like a CMS collection path) doesn't, it catches the 404 and renders that part as plain text instead of a broken link.

← Back to the course

Also part of these courses