# Breadcrumbs

- Entry point: `@koobiq/components/breadcrumbs`
- NgModule: `KbqBreadcrumbsModule`
- Page: https://koobiq.io/en/components/breadcrumbs/overview

## Overview

Breadcrumbs are a navigation element that helps users easily orient themselves on a website and understand their current location relative to the main page.

**Example: Breadcrumbs overview** (`breadcrumbs-overview`)

```ts breadcrumbs-overview-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'breadcrumbs-overview-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item
                    [routerLink]="breadcrumb.url"
                    [queryParams]="{ queryParams: 'queryParam' }"
                    [fragment]="'fragment'"
                    [text]="breadcrumb.label"
                />
            }
        </nav>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsOverviewExample {
    breadcrumbs = [
        { label: 'Main', url: '/main' },
        { label: 'Standards', url: '/main/standards' },
        { label: 'Advanced Encryption Standard', url: '/main/standards/advanced-encryption-standard' },
        { label: 'Edit', url: '/main/standards/advanced-encryption-standard/edit' }
    ];
}
```

### Sizes

Breadcrumbs come in several sizes to offer more flexibility for adapting to different interfaces.

**Example: Breadcrumbs sizes** (`breadcrumbs-size`)

```ts breadcrumbs-size-example.ts
import { TitleCasePipe } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqDefaultSizes } from '@koobiq/components/core';
import { KbqDd, KbqDl, KbqDt } from '@koobiq/components/dl';

@Component({
    selector: 'breadcrumbs-size-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule,
        KbqDl,
        KbqDt,
        KbqDd,
        TitleCasePipe
    ],
    template: `
        <kbq-dl [vertical]="true">
            @for (size of sizes; track size) {
                <kbq-dt class="kbq-text-normal">{{ size | titlecase }}</kbq-dt>
                <kbq-dd>
                    <nav kbq-breadcrumbs [size]="size">
                        @for (breadcrumb of breadcrumbs; track breadcrumb; let last = $last) {
                            <kbq-breadcrumb-item
                                [routerLink]="breadcrumb.url"
                                [queryParams]="{ queryParams: 'queryParams' }"
                                [fragment]="'fragment'"
                                [text]="breadcrumb.label"
                            />
                        }
                    </nav>
                </kbq-dd>
            }
        </kbq-dl>
    `,
    styles: `
        :host .kbq-dl.kbq-dl_vertical .kbq-dd {
            max-width: 100%;
            container-type: inline-size;
            box-sizing: border-box;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsSizeExample {
    breadcrumbs = [
        { label: 'Information Security', url: '/information-security' },
        { label: 'Access Control', url: '/information-security/access-control' },
        { label: 'Authorization', url: '/information-security/access-control/authorization' },
        { label: 'RBAC', url: '/information-security/access-control/authorization/rbac' },
        { label: 'Roles', url: '/information-security/access-control/authorization/rbac/roles' }
    ];
    sizes: KbqDefaultSizes[] = ['compact', 'normal', 'big'];
}
```

### Dropdown Elements in Breadcrumbs

**Example: Breadcrumbs sizes** (`breadcrumbs-dropdown`)

```ts breadcrumbs-dropdown-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqButtonModule } from '@koobiq/components/button';
import { KbqDropdownModule } from '@koobiq/components/dropdown';
import { KbqIconModule } from '@koobiq/components/icon';

@Component({
    selector: 'breadcrumbs-dropdown-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule,
        KbqButtonModule,
        KbqIconModule,
        KbqDropdownModule
    ],
    template: `
        <nav kbq-breadcrumbs>
            <kbq-breadcrumb-item
                routerLink="./info-sec"
                text="Information Security"
                [queryParams]="{ queryParams: 'queryParams' }"
                [fragment]="'fragment'"
            />

            <kbq-breadcrumb-item
                routerLink="./access-control"
                text="Access Control"
                [queryParams]="{ queryParams: 'queryParams' }"
                [fragment]="'fragment'"
            />

            <kbq-breadcrumb-item
                routerLink="./authorization"
                text="Authorization"
                [queryParams]="{ queryParams: 'queryParams' }"
                [fragment]="'fragment'"
            />

            <kbq-breadcrumb-item>
                <div *kbqBreadcrumbView>
                    <button kbq-button kbqBreadcrumb [kbqDropdownTriggerFor]="siblingsListDropdown">
                        Access Control
                        <i kbq-icon="kbq-chevron-down-s_16"></i>
                    </button>
                </div>
            </kbq-breadcrumb-item>
        </nav>

        <kbq-dropdown #siblingsListDropdown="kbqDropdown">
            <a kbq-dropdown-item routerLink="./RBAC">RBAC</a>
            <a kbq-dropdown-item routerLink="./ABAC">ABAC</a>
        </kbq-dropdown>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsDropdownExample {}
```

### Custom Template

**Example: Breadcrumbs custom-template** (`breadcrumbs-custom-template`)

```ts breadcrumbs-custom-template-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqButtonModule } from '@koobiq/components/button';
import { KbqIconModule } from '@koobiq/components/icon';

@Component({
    selector: 'breadcrumbs-custom-template-example',
    imports: [
        RouterLink,
        KbqButtonModule,
        KbqIconModule,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item [routerLink]="breadcrumb.url" [text]="breadcrumb.label">
                    <a
                        *kbqBreadcrumbView
                        tabindex="-1"
                        kbq-button
                        kbqBreadcrumb
                        [focusable]="!$last"
                        [routerLink]="breadcrumb.url"
                        [disabled]="$last"
                        [attr.aria-current]="$last ? 'page' : null"
                    >
                        {{ breadcrumb.label }}
                        <i kbq-icon="kbq-file-code-o_16"></i>
                    </a>
                </kbq-breadcrumb-item>
            }
        </nav>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsCustomTemplateExample {
    breadcrumbs = [
        { label: 'Information Security', url: '/information-security' },
        { label: 'Access Control', url: '/information-security/access-control' },
        { label: 'Authorization', url: '/information-security/access-control/authorization' },
        { label: 'RBAC', url: '/information-security/access-control/authorization/rbac' },
        { label: 'Roles', url: '/information-security/access-control/authorization/rbac/roles' }
    ];
}
```

Two directives shape what a trail renders. `kbqBreadcrumbView` replaces the content of a single item, and `kbqBreadcrumbsSeparator` replaces the separator of the whole trail.

### Number of Visible Items

`max` caps how many items the trail shows at once; the rest collapse into a dropdown behind an expand button. The button takes one of the slots, so `[max]="4"` renders three items plus the button. `[max]="null"` removes the cap and leaves the collapsing to the available width alone.

Give every `kbq-breadcrumb-item` a `routerLink`: the dropdown rebuilds the collapsed items from `text` and `routerLink`, so an item without a destination becomes a row that leads nowhere.

### Disabled State

`disabled` turns the whole trail read-only: every item and the expand button stop navigating and leave the tab order.

```ts
@Component({
    template: `
        <nav
            kbq-breadcrumbs
            [disabled]="isReadOnly"
            >...
        </nav>
    `
})
```

Individual items have their own `disabled` input, which does the same for one item only.

### Item Truncation

Breadcrumb items can have names of varying lengths.\
The modes below are recipes rather than component inputs: each one is a block of CSS the consuming application applies to the rendered items, and the examples carry it in their own `styles`. Copy the styles along with the markup.

#### Truncation by Name Length

A standard truncation method where the name is cut off after the first 14 characters.

**Example: Breadcrumbs Truncate Head Items** (`breadcrumbs-truncate-head-items`)

```ts breadcrumbs-truncate-head-items-example.ts
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'breadcrumbs-truncate-head-items-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav class="example-breadcrumbs_truncate-by-length" kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item
                    [routerLink]="breadcrumb.url"
                    [queryParams]="{ queryParams: 'queryParam' }"
                    [fragment]="'fragment'"
                    [text]="breadcrumb.label"
                />
            }
        </nav>
    `,
    styles: `
        /* A width is all a breadcrumb needs to truncate: the button already ships the contract
           (\`.kbq-button-wrapper\` is a flex box with \`min-width: 0\`, \`.kbq-button-text\` carries the
           ellipsis), and overriding the wrapper is what used to break it. */
        .example-breadcrumbs_truncate-by-length {
            .kbq-breadcrumb-item {
                max-width: 124px;
            }
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None
})
export class BreadcrumbsTruncateHeadItemsExample {
    breadcrumbs = [
        { label: 'Components', url: '/components' },
        { label: 'Commit', url: '/components/commit' },
        {
            label: 'cacb86c728451b57740706d19429e6629140b7c5',
            url: '/components/commit/cacb86c728451b57740706d19429e6629140b7c5'
        }
    ];
}
```

#### Truncation to the Tail

Used in cases where highlighting a unique identifier at the end of the name is necessary.

**Example: Breadcrumbs Truncate Tail Items** (`breadcrumbs-truncate-tail-items`)

```ts breadcrumbs-truncate-tail-items-example.ts
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'breadcrumbs-truncate-tail-items-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav class="example-breadcrumbs_truncate-last-by-length-reverse" kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item
                    [routerLink]="breadcrumb.url"
                    [queryParams]="{ queryParams: 'queryParams' }"
                    [fragment]="'fragment'"
                    [text]="breadcrumb.label"
                />
            }
        </nav>
    `,
    styles: `
        .example-breadcrumbs_truncate-last-by-length-reverse {
            .kbq-breadcrumb-item:last-of-type {
                max-width: 96px;

                /* The button already truncates its label; this only moves the ellipsis to the front, so the
                   part that tells the reports apart stays readable. */
                .kbq-button-text {
                    direction: rtl;
                }
            }
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None
})
export class BreadcrumbsTruncateTailItemsExample {
    breadcrumbs = [
        { label: 'Main', url: '/main' },
        { label: 'Users', url: '/main/users' },
        { label: 'Report №123456789', url: '/main/users/report-123456789' }
    ];
}
```

#### Middle Section Truncation

For cases when it is necessary to highlight the beginning and the end of the title.

**Example: Breadcrumbs Truncate Center Items** (`breadcrumbs-truncate-center-items`)

```ts breadcrumbs-truncate-center-items-example.ts
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqButtonModule } from '@koobiq/components/button';
import { PopUpPlacements } from '@koobiq/components/core';
import { KbqEllipsisCenterModule } from '@koobiq/components/ellipsis-center';
import { KbqToolTipModule } from '@koobiq/components/tooltip';

@Component({
    selector: 'breadcrumbs-truncate-center-items-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule,
        KbqEllipsisCenterModule,
        KbqToolTipModule,
        KbqButtonModule
    ],
    template: `
        <nav class="example-breadcrumbs_truncate-last-by-center" size="compact" kbq-breadcrumbs>
            <kbq-breadcrumb-item routerLink="./groups" text="Groups" />
            <kbq-breadcrumb-item routerLink="./users" text="Users" />

            <kbq-breadcrumb-item text="Report dated 28.08.2018">
                <ng-container *kbqBreadcrumbView>
                    <a routerLink="./report" tabindex="-1">
                        <button aria-current="page" disabled kbq-button kbqBreadcrumb>
                            <span
                                kbqEllipsisCenter="Report dated 28.08.2018"
                                [minVisibleLength]="15"
                                [charWidth]="5"
                                [kbqPlacementPriority]="PopUpPlacements.Bottom"
                                [kbqTooltipArrow]="false"
                            ></span>
                        </button>
                    </a>
                </ng-container>
            </kbq-breadcrumb-item>
        </nav>
    `,
    styles: `
        /* A width is all the breadcrumb needs: the button already ships the truncation contract, and
           kbqEllipsisCenter measures the width the button leaves it. */
        .example-breadcrumbs_truncate-last-by-center {
            .kbq-breadcrumb-item:last-of-type {
                max-width: 124px;
            }
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    encapsulation: ViewEncapsulation.None
})
export class BreadcrumbsTruncateCenterItemsExample {
    protected readonly PopUpPlacements = PopUpPlacements;
}
```

#### Using Abbreviations

For cases where a name can be replaced with a shortened version using a well-known abbreviation. It is important that this abbreviation is already familiar to the service's user audience.

**Example: Breadcrumbs Truncate By Abbreviation Items** (`breadcrumbs-truncate-by-abbrev-items`)

```ts breadcrumbs-truncate-by-abbrev-items-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqButtonModule } from '@koobiq/components/button';
import { PopUpPlacements } from '@koobiq/components/core';
import { KbqToolTipModule } from '@koobiq/components/tooltip';

@Component({
    selector: 'breadcrumbs-truncate-by-abbrev-items-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule,
        KbqButtonModule,
        KbqToolTipModule
    ],
    template: `
        <nav kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item
                    [routerLink]="breadcrumb.url"
                    [queryParams]="{ queryParams: breadcrumb }"
                    [fragment]="breadcrumb.longText"
                    [text]="breadcrumb.longText"
                >
                    <a *kbqBreadcrumbView tabindex="-1" [routerLink]="breadcrumb.url">
                        <button
                            kbq-button
                            kbqBreadcrumb
                            [attr.aria-current]="$last ? 'page' : null"
                            [disabled]="$last"
                            [kbqPlacementPriority]="PopUpPlacements.Bottom"
                            [kbqTooltipArrow]="false"
                            [kbqTooltip]="breadcrumb.longText"
                            [kbqTooltipDisabled]="!breadcrumb.shortText"
                        >
                            {{ breadcrumb.shortText || breadcrumb.longText }}
                        </button>
                    </a>
                </kbq-breadcrumb-item>
            }
        </nav>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsTruncateByAbbrevItemsExample {
    breadcrumbs = [
        { longText: 'Main', url: '/main' },
        { longText: 'Reviews', url: '/main/reviews' },
        {
            longText: 'Advanced Encryption Standard',
            shortText: 'AES',
            url: '/main/reviews/advanced-encryption-standard'
        }
    ];
    protected readonly PopUpPlacements = PopUpPlacements;
}
```

#### Negative Margin

By default, the breadcrumb panel is shifted to the left by `--kbq-breadcrumb-item-negative-margin` using a negative margin. This behavior can be changed using the `firstItemNegativeMargin` property.

For specific breadcrumbs:

```ts
@Component({
    template: `
        <nav
            kbq-breadcrumbs
            [firstItemNegativeMargin]="false"
            >...
        </nav>
    `
})
```

For all breadcrumbs in the module, using **Dependency Injection** with the `kbqBreadcrumbsConfigurationProvider` provider:

```ts
import { kbqBreadcrumbsConfigurationProvider } from '@koobiq/components/breadcrumbs';

@NgModule({
    providers: [
        kbqBreadcrumbsConfigurationProvider({
            firstItemNegativeMargin: false
        })
    ]
})
```

### Line Breaks

Sometimes, the parent container of breadcrumbs may be compressed in width. In such cases, it is recommended either to use truncation and hide items or to wrap items onto a new line.

#### No Line Break Mode

This mode allows breadcrumbs to adjust to the available space.

**Example: Breadcrumbs Auto Wrap Adaptive** (`breadcrumbs-with-auto-wrap-adaptive`)

```ts breadcrumbs-with-auto-wrap-adaptive-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'example-breadcrumbs',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav wrapMode="auto" kbq-breadcrumbs [max]="null">
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item [routerLink]="breadcrumb.url" [text]="breadcrumb.label" />
            }
        </nav>
    `,
    styles: `
        :host {
            display: flex;
            align-items: center;
            justify-content: flex-start;
            max-width: 100%;
            min-width: 137px;
            overflow: hidden;
            container-type: inline-size;
            background: var(--kbq-background-bg);
            padding: var(--kbq-size-l);
            border-radius: var(--kbq-size-l);
            box-shadow: var(--kbq-shadow-card);
            box-sizing: border-box;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleBreadcrumbs {
    breadcrumbs = [
        { label: 'Main', url: '/main' },
        { label: 'Standards', url: '/main/standards' },
        { label: 'Advanced Encryption Standard', url: '/main/standards/advanced-encryption-standard' },
        { label: 'Edit', url: '/main/standards/advanced-encryption-standard/edit' },
        { label: 'Test', url: '/main/standards/advanced-encryption-standard/edit/test' }
    ];
}

@Component({
    selector: 'breadcrumbs-with-auto-wrap-adaptive-example',
    imports: [ExampleBreadcrumbs],
    template: `
        <example-breadcrumbs class="layout-margin-bottom-3xl" />
        <example-breadcrumbs class="layout-margin-bottom-l" [style.width.px]="480" />
        <div class="example-description layout-margin-bottom-3xl">
            Automatic truncation is used as a basis when middle items are hidden due to lack of free space.
        </div>

        <example-breadcrumbs class="layout-margin-bottom-l" [style.width.px]="320" />
        <div class="example-description layout-margin-bottom-3xl">
            If space becomes even smaller, the leftmost breadcrumb level is also hidden, leaving only the rightmost
            level visible.
        </div>

        <example-breadcrumbs class="layout-margin-bottom-l" [style.width.px]="137" />
        <div class="example-description layout-margin-bottom-3xl">
            Next, breadcrumbs can only reduce in size when the visible item's name is trimmed to 3 characters.
        </div>
    `,
    styles: `
        .example-description {
            color: var(--kbq-foreground-contrast-secondary);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsWithAutoWrapAdaptiveExample {}
```

##### When is a Line Break Needed?

If it is necessary to display the breadcrumb values without truncation or hiding items, wrapping items onto a new line can be used.

**Example: Breadcrumbs Wrap** (`breadcrumbs-with-wrap`)

```ts breadcrumbs-with-wrap-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'breadcrumbs-with-wrap-example',
    imports: [KbqBreadcrumbsModule],
    template: `
        <div [style.max-width.px]="320">
            <nav wrapMode="wrap" kbq-breadcrumbs [firstItemNegativeMargin]="false">
                @for (breadcrumb of breadcrumbs; track breadcrumb) {
                    <kbq-breadcrumb-item [text]="breadcrumb.label" />
                }
            </nav>
        </div>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsWithWrapExample {
    breadcrumbs = [
        { label: 'Main' },
        { label: 'Standards' },
        { label: 'Advanced Encryption Standard' },
        { label: 'Edit' },
        { label: 'Test' }
    ];
}
```

### Accessibility

The trail is a navigation landmark. On `<kbq-breadcrumbs>` the `navigation` role is written for you; `<nav kbq-breadcrumbs>` carries it already.

Its accessible name comes from the active locale. Whenever a page renders more than one trail, name them apart with `aria-label` so assistive technology can tell which is which:

```html
<nav kbq-breadcrumbs aria-label="Section navigation">...</nav>
```

The default separator is hidden from assistive technology, so the punctuation between items is not read out. A separator supplied through `kbqBreadcrumbsSeparator` has to do the same:

```html
<ng-template kbqBreadcrumbsSeparator>
    <span aria-hidden="true">→</span>
</ng-template>
```

The last item of a trail is marked `aria-current="page"`. A trail that does not end at the current page — a detail view reached from a list, for example — can mark the current item itself with the `current` input.

### Keyboard Navigation

| Key                      | Behavior                                                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Tab                      | Navigate to the start of the breadcrumbs: When the focus switches to breadcrumbs, the cursor automatically moves to the first item in the navigation path.                                                                                                                                                                                                                                                    |
| Enter \ Space            | Activates the item. Navigation to a link: If the selected item corresponds to a link to another page, navigation occurs. Expand a dropdown: For items with dropdown lists, the list opens, and the focus shifts to the first item in the list. Trigger an action: If the item has an associated action (e.g., opening a modal window), the action is performed. No action: For other items, no actions occur. |
| Right Arrow \ Left Arrow | Move through items: Allows navigation through the breadcrumb items forward or backward. When reaching the end or start of the list, the cursor cyclically moves to the opposite end.                                                                                                                                                                                                                          |
| Bottom Arrow             | Expanding a dropdown list: if the current item contains a nested list, it will be expanded.                                                                                                                                                                                                                                                                                                                   |
| Home                     | Go to start: moves the focus to the first navigation item.                                                                                                                                                                                                                                                                                                                                                    |
| End                      | Go to end: moves the focus to the last focusable navigation item. The item of the current page is not focusable, so the focus lands on the one before it.                                                                                                                                                                                                                                                     |

## API

### Components

#### KbqBreadcrumbItem (component)

Component represents an individual breadcrumb item with optional support for router navigation and styling.

```ts
@Component({ selector: 'kbq-breadcrumb-item' })
class KbqBreadcrumbItem {
    readonly text = input<string>('');
    readonly disabled = input<boolean>(false);
    readonly current = input<boolean>(false);
    readonly customTemplateRef: Signal<TemplateRef<unknown> | undefined>;
    readonly routerLink: RouterLink | null;
}
```

- `[text]`: `string` — The text displayed for the breadcrumb item.
  This text will be shown if breadcrumb item is hidden in dropdown.
- `[disabled]`: `boolean` — Indicates whether the breadcrumb item is disabled.
- `[current]`: `boolean` — Indicates whether the breadcrumb item is the current/active item, which the trail exposes as
  `aria-current="page"`. The last item of a trail is current regardless of this input.
- `customTemplateRef`: `Signal<TemplateRef<unknown> | undefined>` — A reference to a custom template provided for the breadcrumb item content.
  The template can be used to override the default appearance of the breadcrumb.
- `routerLink`: `RouterLink | null` — An optional `RouterLink` instance for navigating to a specific route.
  Injected from the host element, if available and projecting to the hidden breadcrumb item in dropdown.

#### KbqBreadcrumbs (component)

```ts
@Component({ selector: 'kbq-breadcrumbs,[kbq-breadcrumbs]' })
class KbqBreadcrumbs {
    readonly ariaLabel = input<string | null>(null, {
        alias: 'aria-label'
    });
    readonly firstItemNegativeMargin = input<boolean>(
        this.configuration.firstItemNegativeMargin
    );
    readonly size = input<KbqDefaultSizes>(this.configuration.size);
    readonly max = input<number | null>(this.configuration.max);
    readonly disabled = input<boolean>(false);
    readonly wrapMode = input<KbqBreadcrumbsWrapMode>(
        this.configuration.wrapMode
    );
}
```

- `[aria-label]`: `string | null` — Accessible name of the navigation landmark. Set it whenever a page renders more than one trail, so
  assistive technology can tell them apart. Left unset, the name comes from the active locale.
- `[firstItemNegativeMargin]`: `boolean` — Determines if a negative margin should be applied to the first breadcrumb item. The default comes from
  `KbqBreadcrumbsConfiguration`.
- `[size]`: `KbqDefaultSizes` — Size of the breadcrumbs. Affects font size.
  Default value is taken from the global configuration.
- `[max]`: `number | null` — Maximum number of visible breadcrumb items.
  Remaining items are collapsed into a dropdown if the total exceeds this value.
  Default value is taken from the global configuration.
- `[disabled]`: `boolean` — Indicates whether the breadcrumbs are disabled.
  When disabled, every item and the expand button stop navigating and leave the tab order.
- `[wrapMode]`: `KbqBreadcrumbsWrapMode` — Wrapping behavior of the breadcrumb items.
- `[dir]`: `Direction | null` — Reading direction the arrow keys are mapped against, written onto the host as `dir`. Left unset,
  no attribute is emitted — the element inherits the document direction, and the key mapping follows
  the ambient CDK `Directionality`.
- `[loop]`: `boolean` — Whether the arrow keys wrap around, from the last item to the first and back.
- `[localeOverrides]`: `KbqPartialLocaleData | undefined` — Localized strings for this element and its subtree, keyed by locale section. Every key is optional at
  every depth.

### Directives

#### KbqBreadcrumbButton (directive)

Directive to style and configure buttons used as breadcrumb items.
- Takes part in the roving focus of `KbqBreadcrumbs`: the arrow keys move between the items.
- Optionally injects `KbqButton` to customize its style for breadcrumb usage.
- Sets `type="button"` on a `<button>` host, so a breadcrumb never submits a surrounding form.

```ts
@Directive({ selector: '[kbq-button][kbqBreadcrumb]' })
class KbqBreadcrumbButton {}
```

- `[focusable]`: `boolean` — Whether the item takes part in the roving focus. The arrow keys skip an item that does not, and a click
  does not focus it.

#### KbqBreadcrumbsSeparator (directive)

```ts
@Directive({ selector: 'ng-template[kbqBreadcrumbsSeparator]' })
class KbqBreadcrumbsSeparator {
    readonly templateRef: TemplateRef<unknown>;
}
```

#### KbqBreadcrumbView (directive)

Directive provides a way to define a custom template for breadcrumb rendering, leveraging TemplateRef

```ts
@Directive({ selector: '[kbqBreadcrumbView]' })
class KbqBreadcrumbView {
    readonly templateRef: TemplateRef<unknown>;
}
```

### Types

#### KbqBreadcrumbsConfiguration (type)

```ts
type KbqBreadcrumbsConfiguration = {
    max: number | null;
    size: KbqDefaultSizes;
    firstItemNegativeMargin: boolean;
    wrapMode: KbqBreadcrumbsWrapMode;
};
```

- `max`: `number | null` — Specifies the maximum number of breadcrumb items to display.
  - If a number is provided, only that many items will be shown.
  - If `null`, no limit is applied, and all breadcrumb items are displayed.
- `firstItemNegativeMargin`: `boolean` — Determines if a negative margin should be applied to the first breadcrumb item.
- `wrapMode`: `KbqBreadcrumbsWrapMode` — Manages breadcrumb items when space is limited:
  - `auto`: Adjusts based on space and item count.
  - `wrap`: Moves items to the next line if needed.
  - `none`: Prevents wrapping, allowing overflow.

#### KbqBreadcrumbsWrapMode (type)

```ts
type KbqBreadcrumbsWrapMode = 'auto' | 'wrap' | 'none';
```

#### KbqRovingFocusOrientation (type)

Axis a roving-focus group navigates along.

```ts
type KbqRovingFocusOrientation = 'horizontal' | 'vertical';
```

### Constants

#### KBQ_BREADCRUMBS_CONFIGURATION (const)

Breadcrumbs options global configuration provider.

```ts
const KBQ_BREADCRUMBS_CONFIGURATION: InjectionToken<KbqBreadcrumbsConfiguration>;
```

#### kbqBreadcrumbsConfigurationProvider (const)

Utility provider for `KBQ_BREADCRUMBS_CONFIGURATION`.

```ts
const kbqBreadcrumbsConfigurationProvider: (
    configuration: Partial<KbqBreadcrumbsConfiguration>
) => Provider;
```

## Examples

### Selectable Text

Uses a custom template to allow text selection and provide a one-click copy action on the current breadcrumb item.

**Example: Breadcrumbs selectable text** (`breadcrumbs-selectable-text`)

```ts breadcrumbs-selectable-text-example.ts
import { Clipboard } from '@angular/cdk/clipboard';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';
import { KbqButtonModule } from '@koobiq/components/button';
import { KbqIconModule } from '@koobiq/components/icon';

@Component({
    selector: 'breadcrumbs-selectable-text-example',
    imports: [
        RouterLink,
        KbqButtonModule,
        KbqIconModule,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav kbq-breadcrumbs [firstItemNegativeMargin]="false">
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item [routerLink]="breadcrumb.url" [text]="breadcrumb.label">
                    <a
                        *kbqBreadcrumbView
                        tabindex="-1"
                        kbq-button
                        kbqBreadcrumb
                        [focusable]="!$last"
                        [routerLink]="breadcrumb.url"
                        [disabled]="$last"
                        [attr.aria-current]="$last ? 'page' : null"
                    >
                        <span class="example__selectable-label">{{ breadcrumb.label }}</span>
                        <div class="example-item__copy-icon" (click)="copyToClipboard($event, breadcrumb.label)">
                            <i kbq-icon="kbq-square-multiple-o_16"></i>
                        </div>
                    </a>
                </kbq-breadcrumb-item>
            }
        </nav>
    `,
    styles: [
        `
            .example__selectable-label {
                -webkit-user-select: text;
                user-select: text;
            }

            .example-item__copy-icon {
                position: absolute;
                right: 0;
                top: 0;
                bottom: 0;
                display: flex;
                align-items: center;
                padding: 0 var(--kbq-size-xs);
                background: linear-gradient(
                    to right,
                    transparent,
                    var(--kbq-background-overlay-inverse) var(--kbq-size-s)
                );
                border-radius: var(--kbq-size-xxs);
                opacity: 0;
                pointer-events: none;
                transition: opacity 0.2s ease;
            }

            a:hover .example-item__copy-icon,
            a:focus-visible .example-item__copy-icon {
                opacity: 1;
                pointer-events: auto;
            }
        `
    ],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsSelectableTextExample {
    private readonly clipboard = inject(Clipboard, { optional: true });

    protected readonly breadcrumbs = [
        { label: 'Information Security', url: '/information-security' },
        { label: 'Access Control', url: '/information-security/access-control' },
        { label: 'Authorization', url: '/information-security/access-control/authorization' },
        { label: 'RBAC', url: '/information-security/access-control/authorization/rbac' },
        { label: 'Roles', url: '/information-security/access-control/authorization/rbac/roles' }
    ];

    protected copyToClipboard(event: MouseEvent, text: string): void {
        event.preventDefault();
        event.stopImmediatePropagation();
        this.clipboard?.copy(text);
    }
}
```

### Working with Routing

This example demonstrates how to dynamically generate breadcrumbs based on the current route.
It uses a subscription to [`router`](https://angular.dev/api/router/Router) events to track changes and build the navigation structure.

**Example: Breadcrumbs Routing** (`breadcrumbs-routing`)

```ts breadcrumbs-routing-example.ts
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs';

@Component({
    selector: 'breadcrumbs-routing-example',
    imports: [
        RouterLink,
        KbqBreadcrumbsModule
    ],
    template: `
        <nav kbq-breadcrumbs>
            @for (breadcrumb of breadcrumbs; track breadcrumb) {
                <kbq-breadcrumb-item [routerLink]="breadcrumb.url" [text]="breadcrumb.label" />
            }
        </nav>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class BreadcrumbsRoutingExample {
    readonly router = inject(Router);
    readonly activatedRoute = inject(ActivatedRoute);
    breadcrumbs: { label: string; url: string }[] = this.buildBreadcrumbs(this.activatedRoute.root);

    /* react on dynamic changes on routing events. Cannot possible to show in docs
    breadcrumbs: Observable<{ label: string; url: string }[]>;
    constructor() {
        this.breadcrumbs = this.router.events.pipe(
            filter((event) => event instanceof NavigationEnd),
            map(() => this.buildBreadcrumbs(this.activatedRoute.root)),
            takeUntilDestroyed()
        );
    }*/

    private buildBreadcrumbs(
        route: ActivatedRoute,
        url: string = '',
        breadcrumbs: { label: string; url: string }[] = []
    ): { label: string; url: string }[] {
        const children: ActivatedRoute[] = route.children;

        if (children.length === 0) {
            return breadcrumbs;
        }

        children.forEach((child) => {
            const routeURL: string = child.snapshot.url.map((segment) => segment.path).join('/');

            if (routeURL) {
                url += `/${routeURL}`;
            }

            const label =
                child.snapshot.data['breadcrumb'] ||
                (child.snapshot.url.length && child.snapshot.url[0].path) ||
                'test';

            if (label) {
                breadcrumbs.push({ label, url });
            }

            return this.buildBreadcrumbs(child, url, breadcrumbs);
        });

        return breadcrumbs;
    }
}
```
