Breadcrumb
The WAI-ARIA APG breadcrumb: a <nav> landmark holding an ordered list of links, the current page carrying aria-current="page". The APG defines no keyboard behavior for a breadcrumb — crumbs are plain links in the Tab order, so no roving tabindex is invented here. (Neither DevExtreme nor Angular Material/CDK ships a breadcrumb at all; the parity references are Kendo and PrimeNG.)
When the container runs out of room the oldest middle crumbs collapse first — the first and last crumb always stay visible — and unlike the references the collapsed crumbs stay reachable: the ellipsis opens them as real links. The fitting arithmetic is core's pure fitToolbarItems, measured against the breadcrumb's own box, never the window.
Getting started
One flat items trail. url crumbs are real links (middle-click and copy-address work; preventDefault() in itemClick hands navigation to a router), the last crumb is never interactive and disabled crumbs stay visible but inert.
Last click: —
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeBreadcrumb } from '@oge-ui/navigation';
import type { OgeBreadcrumbItemData, OgeBreadcrumbItemClickEvent } from '@oge-ui/navigation';
@Component({
selector: 'demo-root',
imports: [OgeBreadcrumb],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- The APG breadcrumb: a nav landmark holding an ordered list of
links, the current page carrying aria-current="page". The last crumb is
never interactive — you are already there — and disabled crumbs stay
visible but inert. No roving tabindex: the APG defines no keyboard
behavior for a breadcrumb, so none is invented. -->
<oge-breadcrumb [items]="trail" (itemClick)="go($event)" />
`,
})
export class Demo {
protected readonly trail: OgeBreadcrumbItemData[] = [
{ text: 'Home', key: 'home', url: '/', icon: 'M2 8 8 2l6 6M4 7v7h8V7' },
{ text: 'Products', key: 'products', url: '/products' },
{ text: 'Keyboards', key: 'keyboards', url: '/products/keyboards' },
{ text: 'Mechanical' },
];
protected go(event: OgeBreadcrumbItemClickEvent): void {
console.log(event.key, event.index);
}
}Declarative items
Both APIs, one rule: declarative children render first, then the items input — the house merge order shared across the suite.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeBreadcrumb, OgeBreadcrumbItem } from '@oge-ui/navigation';
@Component({
selector: 'demo-root',
imports: [OgeBreadcrumb, OgeBreadcrumbItem],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- Declarative children come first, then the items input — the
house merge order. A flat list, never nested. -->
<oge-breadcrumb>
<oge-breadcrumb-item text="Home" key="home" url="/" />
<oge-breadcrumb-item text="Reports" key="reports" url="/reports" />
<oge-breadcrumb-item text="Q3 summary" />
</oge-breadcrumb>
`,
})
export class Demo {}Collapse modes
auto (default) collapses against the breadcrumb's own container; the ellipsis menu keeps the hidden crumbs reachable as real links. wrap breaks onto rows and none keeps one scrollable row. Drag the range to squeeze it.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeBreadcrumb } from '@oge-ui/navigation';
import type { OgeBreadcrumbItemData } from '@oge-ui/navigation';
@Component({
selector: 'demo-root',
imports: [OgeBreadcrumb],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- collapseMode 'auto' (default) measures the breadcrumb's OWN
container, never the window. When room runs out the OLDEST middle crumbs
collapse first — first and last always stay visible — and unlike the
references the collapsed crumbs remain reachable: the ellipsis opens
them as real links. 'wrap' breaks onto rows, 'none' keeps one
scrollable row. -->
<oge-breadcrumb [items]="trail" collapseMode="auto" />
`,
})
export class Demo {
protected readonly trail: OgeBreadcrumbItemData[] = [
{ text: 'Home', url: '/' },
{ text: 'Products', url: '/products' },
{ text: 'Peripherals', url: '/products/peripherals' },
{ text: 'Keyboards', url: '/products/keyboards' },
{ text: 'Mechanical' },
];
}Templates
The item template replaces the crumb's interior only — link/current/disabled semantics stay with the component. The separator template renders aria-hidden: a separator is decoration, never content.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeBreadcrumb, OgeBreadcrumbItemTemplate, OgeBreadcrumbSeparatorTemplate } from '@oge-ui/navigation';
import type { OgeBreadcrumbItemData } from '@oge-ui/navigation';
@Component({
selector: 'demo-root',
imports: [OgeBreadcrumb, OgeBreadcrumbItemTemplate, OgeBreadcrumbSeparatorTemplate],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- The item template replaces the crumb's interior only — the
link/current/disabled element semantics stay with the component. The
separator template renders aria-hidden: a separator is decoration. -->
<oge-breadcrumb [items]="trail">
<ng-template ogeBreadcrumbItemTemplate let-item let-last="last">
<strong [style.opacity]="last ? 1 : 0.75">{{ item.text }}</strong>
</ng-template>
<ng-template ogeBreadcrumbSeparatorTemplate>·</ng-template>
</oge-breadcrumb>
`,
})
export class Demo {
protected readonly trail: OgeBreadcrumbItemData[] = [
{ text: 'Home', url: '/' },
{ text: 'Library', url: '/library' },
{ text: 'Data' },
];
}Configuration
Suite-wide defaults for collapseMode plus every user-facing string — the nav landmark's label and the ellipsis button's label — via provideOgeBreadcrumbConfig(), overridable per instance with [messages].
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { OgeBreadcrumb, provideOgeBreadcrumbConfig } from '@oge-ui/navigation';
import type { OgeBreadcrumbItemData } from '@oge-ui/navigation';
// Every user-facing string lives in the messages block — the nav
// landmark's label and the ellipsis button's label included.
export const BREADCRUMB_PROVIDERS = [
provideOgeBreadcrumbConfig({
collapseMode: 'auto',
messages: { breadcrumb: 'İçerik haritası', collapsed: 'Gizli öğeleri göster' },
}),
];
@Component({
selector: 'demo-root',
imports: [OgeBreadcrumb],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<oge-breadcrumb [items]="trail" />
`,
})
export class Demo {
protected readonly trail: OgeBreadcrumbItemData[] = [
{ text: 'Giriş', url: '/' },
{ text: 'Raporlar' },
];
}