How to Build Accessible Manual and Dynamic Breadcrumbs in Webflow
This tutorial provides a comprehensive guide to constructing robust breadcrumb navigation systems within Webflow, moving beyond simple visual aids to create fully accessible and structurally sound interface elements. The presenter, Francesco from SupaSaito, demonstrates how to implement two distinct solutions: a manually configured component designed for sites with shallow architectures, and a dynamic, automated system ideal for complex, nested CMS projects. By following this workflow, developers ensure their navigation is not only aesthetically flexible via Webflow components but also rigorously optimized for screen readers and search engine organization through the use of semantic ordered lists and ARIA attributes.
The first segment details the engineering of the manual breadcrumb, emphasizing the importance of component properties for maintaining design consistency while allowing for content flexibility. Viewers learn to build a reusable component that supports up to four levels of navigation, utilizing visibility properties to toggle between various separators—such as CSS-generated slashes, icons, or text characters—without altering the core structure. Crucially, this section addresses usability best practices by implementing specific logic to disable interaction for non-clickable intermediate paths, ensuring a seamless user experience that avoids broken links.
The final portion of the tutorial elevates the design into a scalable, automated solution powered by custom JavaScript that dynamically generates breadcrumb trails based on the active URL structure. This advanced method eliminates the need for manual updates on every page by automatically detecting path segments, formatting text labels from slugs, and verifying link validity to handle "dead" paths intelligently. Ultimately, the viewer will master the ability to deploy a "set-and-forget" navigation system that adapts to CMS layouts and custom folder structures, significantly reducing long-term site maintenance.
Key Takeaways
- Accessibility and Semantic Structure: The tutorial emphasizes constructing breadcrumbs using
<nav>tags witharia-label="breadcrumb"and ordered lists (<ol>) to correctly communicate hierarchy to screen readers, while marking the active page witharia-current="page". - Strategic Folder Nesting: To support deep breadcrumb structures, the video demonstrates how to nest CMS template pages inside static folders (e.g., placing blog posts under a "blog" folder), creating logical URL paths (e.g.,
blog/posts/slug) that enhance SEO and site organization. - Component Property Architecture: Viewers learn to create highly flexible components by grouping properties such as "Visibility," "Text," and "Link," allowing for the manual customization of visual separators and navigation depth without detaching the instance from the main component.
- Handling Non-Clickable Segments: For URL paths that act as structural containers rather than active pages (like
/posts/), the guide teaches a method to render them as plain text usingaria-disabled="true"and CSS, preventing users from interacting with broken links. - Automated URL Parsing: The automatic solution utilizes a JavaScript code embed that splits the current URL into segments, dynamically generating list items and checking for 404 errors to decide whether a segment should be a clickable link or a static text label.
Timestamps
- 03:21 - Create a new static folder (e.g., "blog") to act as the parent directory for nested URL structures.
- 03:34 - Set the "Parent Folder" of CMS template pages to the newly created static folder to achieve nested URLs (e.g.,
domain.com/blog/post-slug). - 05:32 - Set the breadcrumb wrapper tag to
<nav>and add the attributearia-label="breadcrumb"for accessibility. - 05:48 - Add an ordered list
<ol>element to define the semantic structure of the navigation items. - 08:51 - Mark image separators as "decorative" in element settings so screen readers ignore them.
- 09:18 - Add the custom attribute
aria-hidden="true"to text separators to prevent screen readers from announcing them. - 09:51 - Insert a Code Embed with CSS to generate visual separators using pseudo-elements (e.g., forward slashes).
- 11:37 - Add the attribute
aria-current="page"to the link representing the final, active item in the breadcrumb. - 11:50 - Convert the breadcrumb wrapper into a reusable Webflow Component (
Cmd+Shift+A). - 12:42 - Create and assign "Visibility" and "Text" properties to the component elements for customization.
- 16:15 - Create "Visibility" properties for intermediate list items to allow manual toggling of navigation depth.
- 19:50 - Add the
aria-disabledattribute to links that act as structural placeholders (ghost links) rather than active pages. - 20:44 - Update the CSS in the Code Embed to remove pointer events and styling from links marked as
aria-disabled="true". - 23:19 - Add the custom attribute
fc-breadcrumb="component"to the main wrapper to initialize the automatic script. - 23:30 - Add the custom attribute
fc-breadcrumb="last-level"to the list item representing the current page. - 23:43 - Insert the JavaScript logic via a Code Embed to automatically parse the URL and generate the breadcrumb trail.
Masterclass: Building Accessible Breadcrumbs in Webflow
Part 1: Establishing the Site Structure
Reference: 01:41 – 04:27
1. Create a Static Parent Folder
- How: Open the Pages panel and create a new folder (e.g., named "Blog").
- Why: This acts as a physical directory to house your CMS pages, enabling a nested URL structure rather than a flat one.
2. Nest CMS Templates
- How: Go to the settings of your CMS Template Page (e.g., Blog Posts). In the "Parent Folder" dropdown, select the folder created in Step 1. Repeat for Category pages if applicable.
- Why: This changes the URL structure from
domain.com/post-slugtodomain.com/blog/posts/post-slug. This layering is essential for SEO and provides the logical hierarchy needed for a deep breadcrumb trail.
Part 2: Building the Manual Breadcrumb Component
Reference: 04:28 – 16:35
3. Set Up the Semantic Wrapper
- How: Create a Div block named
breadcrumb. In Element Settings, set the tag to<nav>and add the attributearia-label="breadcrumb". - Why: This specifically tells screen readers that this element is a navigation landmark for breadcrumbs, adhering to accessibility standards.
4. Create the List Structure
- How: Inside the wrapper, add an Ordered List (
<ol>) namedbreadcrumb-list. Style it withdisplay: flexandgap: 0.5rem. Delete all default list items except one. - Why: An ordered list is required because breadcrumbs represent a specific sequence of steps; an unordered list (
<ul>) would be semantically incorrect.
5. Add Navigation Items and Links
- How: Inside the list item (
breadcrumb-list-item), add a Text Link (breadcrumb-link). Set the text to "Home" initially. - Why: This serves as the root level of your navigation. Using a text link allows for styling states (hover, pressed) and navigation functionality.
6. Implement Visual Separators (Three Methods)
- How: inside the list item, add three distinct elements:
- Icon: An image element (e.g., a chevron). Mark it as "Decorative" in settings.
- Text: A text element with a character (e.g.,
>). Add the attributearia-hidden="true". - CSS: A Code Embed with CSS targeting the list item (
content: "/";).
- Why: Providing three options allows end-users to toggle between styles using properties without rebuilding the component. Attributes like
aria-hiddenensure screen readers ignore these purely visual elements.
7. Define the Active Page
- How: Duplicate the list item to create a 4-level structure. Select the link in the final item and add the attribute
aria-current="page". - Why: This programmatic marker informs assistive technology which link represents the user's current location.
8. Convert to Component & Add Properties
- How: Select the wrapper and press
Cmd+Shift+Ato create a component. Add "Visibility" properties for the separators and list items, and "Text" properties for the links,. Group these properties by level (e.g., "Root", "Level 1"). - Why: Grouping properties makes the component instance clean and manageable, allowing you to toggle levels on and off depending on the page depth.
Part 3: Handling "Ghost" Links (Accessibility Logic)
Reference: 18:56 – 21:55
9. Identify Non-Clickable Paths
- How: In scenarios where an intermediate URL segment exists structurally but isn't a real page (e.g.,
/posts/in/blog/posts/slug), you must disable the link. - Why: Leaving a dead link active creates a bad user experience and confuses screen readers.
10. Apply aria-disabled Attributes
- How: In the component settings, add a new property called
aria-disabled(default: false) applied to the intermediate links. - Why: This allows you to toggle a specific link as "disabled" on a per-instance basis without detaching the component.
11. Style Disabled Links via CSS
- How: Update the component's Code Embed with CSS targeting links with
[aria-disabled="true"]. Setpointer-events: none;and reset text styling (color, decoration). - Why: This visually transforms the link into plain text and prevents mouse interaction, ensuring users cannot click a broken path.
Part 4: Building the Automatic Breadcrumb
Reference: 22:03 – 27:56
12. Prepare the Structure
- How: Duplicate the Manual Component. Remove the
aria-disabledCSS logic and delete all intermediate list items (Levels 1-3), leaving only "Home" and the "Current Page" item,. - Why: The automated system generates the intermediate steps dynamically via code, so manual placeholders are unnecessary.
13. Add Script Hooks (Custom Attributes)
- How:
- Add
fc-breadcrumb="component"to the main wrapper. - Add
fc-breadcrumb="last-level"to the final list item.
- Why: These attributes act as selectors for the JavaScript, telling the code exactly where to inject the generated breadcrumb trail.
14. Inject the Automation Script
- How: Add a Code Embed with the provided JavaScript. The script splits the current URL (
window.location.pathname) by slashes and generates list items for each segment. - Why: This automates the process entirely. The script parses the URL, creates the list items, formats the slug (replacing dashes with spaces), and creates links dynamically.
15. Implement "Smart" 404 Detection
- How: The script includes logic that attempts to fetch the URL for each segment. If the path returns a 404 (doesn't exist), it renders the item as plain text. If it is valid, it renders a link,.
- Why: This automatically handles the "Ghost Link" issue (like
/posts/) without manual configuration, ensuring no broken links exist in the navigation.
16. Final Component Configuration
- How: Convert this new structure into a component (
Breadcrumb Auto). Re-apply visibility properties for separators and text properties for the last level,. - Why: This gives you a "set-it-and-forget-it" component that still allows for minor visual customization and text overrides if the automatic slug is too long.
FAQs
How do I make Webflow breadcrumbs fully accessible?
To ensure accessibility, wrap your breadcrumb container in a <nav> tag with aria-label="breadcrumb" and use an ordered list (<ol>) to strictly define the item hierarchy. You must also apply aria-hidden="true" to visual separators so screen readers ignore them, and add the attribute aria-current="page" to the link representing the active page.
How can I create nested CMS URLs in Webflow (e.g., domain.com/blog/post-name)?
Create a static folder (e.g., "blog") in the Webflow pages panel to act as the parent directory for your collection. Then, navigate to your CMS template page settings and select this static folder from the "Parent Folder" dropdown, which alters the URL structure to nest the template page inside that path.
Is there a way to automate breadcrumbs in Webflow based on the current URL?
Yes, you can use a custom JavaScript code embed that parses the live URL, splits it into segments using slashes, and dynamically generates list items for the breadcrumb trail. This script should be designed to validate each path segment, rendering valid pages as links and non-existent paths as plain text to avoid 404 errors.
How do I handle non-clickable "ghost" links in a breadcrumb trail?
For URL segments that act as structural containers rather than active pages (such as an intermediate /posts/ folder), add the custom attribute aria-disabled="true" to the specific link element. Pair this with custom CSS that removes pointer events and resets text styling, ensuring users cannot click the dead link while maintaining visual consistency.