Skip to content

Conversation

@jdflaugergues
Copy link

@jdflaugergues jdflaugergues commented Nov 21, 2025

Description

This PR improves the VBreadcrumbs component with several accessibility-focused and Material Design–aligned enhancements.
It now uses proper semantic elements (nav, ol, li) for improved screen-reader support and better compliance with accessibility standards.
The component automatically wraps to a new line when the breadcrumb trail becomes too long, preventing layout overflow.
A new maxItems prop allows developers to define how many items can be displayed before collapsing the middle items into an ellipsis.
When collapsed, an optional collapseInMenu prop enables displaying the hidden items inside an accessible dropdown menu.
You can also customize the appearance of the items inside the collapsed menu using the list-item slot. This slot gives you access to each breadcrumb item and its index, allowing you to render any custom content for better UX and visual consistency.
These additions provide cleaner navigation, improved responsiveness, and more robust UX on pages with deep hierarchies.

Markup:

<template>
  <v-app>
    <v-container>
      <v-breadcrumbs :items="items" :total-visible="3" />
      <v-breadcrumbs :items="items" :total-visible="3" collapse-in-menu />
      <v-breadcrumbs :items="items" :total-visible="3" collapse-in-menu>
        <template v-slot:list-item="{ item, index }">
          <v-list-item :key="index" :disabled="item.disabled" :href="item.href">
            <v-list-item-title>
              <span v-if="item.disabled">🔒 </span>{{ item.title }}
            </v-list-item-title>
          </v-list-item>
        </template>
      </v-breadcrumbs>
    </v-container>
  </v-app>
</template>

<script>
  export default {
    name: 'Playground',
    data: () => ({
      items: Array.from({ length: 4 }, (k, v) => ({ title: `Link ${v + 1}`, href: `breadcrumbs_link_${v + 1}`, disabled: v === 2 })),
    }),
  }
</script>

return typeof item === 'string' ? { item: { title: item }, raw: item } : { item, raw: item }
}))
const showEllipsis = computed(() => items.value.length >= props.maxItems)
const enableEllipsis = ref(showEllipsis.value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This prevents the limit from being responsive. Let's say I resize the window and the limit changes, it won't be reflected until the component or page is fully refreshed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. I added a watcher on showEllipsis to handle the responsive behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we leave it like this, it will only support on/off change while someone might want to change the limit based on the available width (e.g. `:total-visible='$vuetify.display.smAndUp ? 4 : 2').

BTW. it might be a personal preference, but I feel like those variables names should swap:

  • showEllipsis » ellipsisEnabled
  • enableEllipsis » showEllipsis or hasEllipsis

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll renamed it

@jdflaugergues jdflaugergues force-pushed the feat/improve-breadcrumbs branch 4 times, most recently from ffc8c40 to 2a3bd3e Compare November 21, 2025 15:37
@jdflaugergues jdflaugergues force-pushed the feat/improve-breadcrumbs branch from 2a3bd3e to c77b459 Compare November 21, 2025 15:44
default: () => (
<VList>
{ items.value.slice(1, items.value.length - 1).map(({ item }, index) => (
<VListItem key={ index } value={ index } component="a" href={ 'href' in item ? item.href : undefined }>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if component="a" does anything here as href should be enough to make it into <a>.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, component="a" is useless. I remove it

<VMenu activator="parent">
{{
default: () => (
<VList>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Would we benefit from menu-props and list-props pass-through (like in VSelect)?
  • #list-item slot could be a reasonable addition

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea. I add it

@jdflaugergues jdflaugergues force-pushed the feat/improve-breadcrumbs branch from 8e6df67 to ffe3825 Compare November 21, 2025 20:57
@jdflaugergues jdflaugergues force-pushed the feat/improve-breadcrumbs branch from ffe3825 to d9084ec Compare November 21, 2025 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants