diff --git a/__snapshots__/breadcrumb/component/chromium/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/component/chromium/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..2c60b3ea190c
Binary files /dev/null and b/__snapshots__/breadcrumb/component/chromium/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/component/firefox/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/component/firefox/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..3937624bdef7
Binary files /dev/null and b/__snapshots__/breadcrumb/component/firefox/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/component/mobile-chrome/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/component/mobile-chrome/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..93da699e6d39
Binary files /dev/null and b/__snapshots__/breadcrumb/component/mobile-chrome/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/chromium-highContrast/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/chromium-highContrast/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..e187caac9287
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/chromium-highContrast/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/__snapshots__/breadcrumb/showcase/chromium/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/chromium/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..9ecdc28bda69
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/chromium/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/chromium/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/chromium/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/chromium/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/__snapshots__/breadcrumb/showcase/firefox/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/firefox/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..2752028de60b
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/firefox/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/firefox/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/firefox/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/firefox/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/__snapshots__/breadcrumb/showcase/mobile-chrome/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/mobile-chrome/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..0bf760c85c38
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/mobile-chrome/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/mobile-chrome/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/mobile-chrome/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/mobile-chrome/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/__snapshots__/breadcrumb/showcase/mobile-safari/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/mobile-safari/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..5b65205f0511
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/mobile-safari/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/mobile-safari/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/mobile-safari/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/mobile-safari/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/__snapshots__/breadcrumb/showcase/webkit/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png b/__snapshots__/breadcrumb/showcase/webkit/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png
new file mode 100644
index 000000000000..58e95462e28a
Binary files /dev/null and b/__snapshots__/breadcrumb/showcase/webkit/DBBreadcrumb-should-match-screenshot-1/DBBreadcrumb-should-match-screenshot.png differ
diff --git a/__snapshots__/breadcrumb/showcase/webkit/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml b/__snapshots__/breadcrumb/showcase/webkit/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
new file mode 100644
index 000000000000..a2d4bc2b5f8d
--- /dev/null
+++ b/__snapshots__/breadcrumb/showcase/webkit/should-have-same-aria-snapshot/DBBreadcrumb-should-have-same-aria-snapshot.yaml
@@ -0,0 +1,36 @@
+- main:
+ - heading "DBBreadcrumb" [level=1]
+ - link "Size"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - link "Separator"
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: ›
+ - link "Category"
+ - listitem: › Current Page
+ - navigation "breadcrumb":
+ - list:
+ - listitem:
+ - link "Home"
+ - listitem:
+ - text: /
+ - link "Category"
+ - listitem: / Current Page
\ No newline at end of file
diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts
index 9177fff99b1d..487da80b794f 100644
--- a/packages/components/scripts/post-build/components.ts
+++ b/packages/components/scripts/post-build/components.ts
@@ -355,6 +355,9 @@ export const getComponents = (): Component[] => [
{
name: 'brand'
},
+ {
+ name: 'breadcrumb'
+ },
{
name: 'input',
overwrites: {
diff --git a/packages/components/src/components/breadcrumb/agent/breadcrumb.agent.lite.tsx b/packages/components/src/components/breadcrumb/agent/breadcrumb.agent.lite.tsx
new file mode 100644
index 000000000000..5daac5173da9
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/agent/breadcrumb.agent.lite.tsx
@@ -0,0 +1,42 @@
+import { DBBreadcrumb } from '../index';
+
+export default function Breadcrumb() {
+ return (
+ <>
+
DBBreadcrumb Documentation Examples
+
+ 1. Default Breadcrumb
+
+
+ Home
+
+
+ Category
+
+ Current Page
+
+
+ 2. Long Breadcrumb Path
+
+
+ Home
+
+
+ Category
+
+
+ Subcategory
+
+
+ Product Group
+
+ Current Product
+
+
+ 3. Single Item
+
+ Current Page
+
+ >
+ );
+}
diff --git a/packages/components/src/components/breadcrumb/breadcrumb.lite.tsx b/packages/components/src/components/breadcrumb/breadcrumb.lite.tsx
new file mode 100644
index 000000000000..38a20ae51280
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/breadcrumb.lite.tsx
@@ -0,0 +1,35 @@
+import {
+ useDefaultProps,
+ useMetadata,
+ useRef,
+ useStore
+} from '@builder.io/mitosis';
+import { cls } from '../../utils';
+import type { DBBreadcrumbProps, DBBreadcrumbState } from './model';
+
+useMetadata({});
+
+useDefaultProps({
+ size: 'small',
+ separator: 'chevron'
+});
+
+export default function DBBreadcrumb(props: DBBreadcrumbProps) {
+ const _ref = useRef(null);
+
+ const state = useStore({});
+
+ return (
+
+ );
+}
diff --git a/packages/components/src/components/breadcrumb/breadcrumb.scss b/packages/components/src/components/breadcrumb/breadcrumb.scss
new file mode 100644
index 000000000000..d0804b21947b
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/breadcrumb.scss
@@ -0,0 +1,136 @@
+@charset "utf-8";
+@use "@db-ux/core-foundations/build/styles/fonts";
+@use "@db-ux/core-foundations/build/styles/variables";
+@use "@db-ux/core-foundations/build/styles/colors";
+@use "@db-ux/core-foundations/build/styles/helpers";
+
+.db-breadcrumb {
+ // Default: Small size
+ .db-breadcrumb-list {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ gap: variables.$db-spacing-fixed-3xs; // 2px gap for small
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ // Breadcrumb items (li elements)
+ li {
+ display: flex;
+ align-items: center;
+ gap: variables.$db-spacing-fixed-3xs; // 2px between separator and item (small)
+ }
+
+ // Link and text styling (small)
+ a,
+ span {
+ display: flex;
+ align-items: center;
+ padding: variables.$db-spacing-fixed-3xs variables.$db-spacing-fixed-2xs; // 2px 4px (small)
+ border-radius: variables.$db-border-radius-xs; // 4px
+ background-color: colors.$db-adaptive-bg-basic-transparent-full-default;
+ color: colors.$db-adaptive-on-bg-basic-emphasis-100-default;
+ font-size: variables.$db-sizing-sm; // 14px (body-sm)
+ line-height: variables.$db-sizing-md; // 20px
+ font-family: var(--db-font-family-sans);
+ font-weight: 400;
+ text-decoration: none;
+ white-space: nowrap;
+ transition: background-color 0.2s ease;
+
+ &:hover,
+ &:focus {
+ background-color: colors.$db-adaptive-bg-basic-transparent-semi-default;
+ text-decoration: underline;
+ }
+
+ &:active {
+ background-color: colors.$db-adaptive-bg-basic-transparent-full-pressed;
+ }
+
+ @media screen and (prefers-reduced-motion: reduce) {
+ transition: none;
+ }
+ }
+
+ // Current page (last item with aria-current="page")
+ li[aria-current="page"] {
+ a,
+ span {
+ font-weight: 700; // Bold for current item
+ cursor: default;
+ pointer-events: none;
+
+ &:hover,
+ &:focus {
+ background-color: colors.$db-adaptive-bg-basic-transparent-full-default;
+ text-decoration: none;
+ }
+ }
+ }
+
+ // Default chevron: apply when the breadcrumb does NOT request a slash
+ &:not([data-separator="slash"])
+ .db-breadcrumb-list
+ li:not(:first-child)::before {
+ content: "›"; // chevron right glyph (U+203A)
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ inline-size: variables.$db-sizing-sm; // 24px (small)
+ block-size: variables.$db-sizing-sm;
+ font-size: variables.$db-sizing-md; // 20px
+ color: colors.$db-adaptive-on-bg-basic-emphasis-100-default;
+ font-weight: 400;
+ }
+
+ // Slash separator override when component has data-separator="slash"
+ &[data-separator="slash"] .db-breadcrumb-list li:not(:first-child)::before {
+ content: "/"; // ASCII slash (0x2F)
+ font-weight: 400;
+ color: colors.$db-adaptive-on-bg-basic-emphasis-100-default;
+
+ /* reduce the inline size so the slash doesn't create extra empty box */
+ inline-size: auto;
+ block-size: auto;
+ font-size: variables.$db-sizing-sm; // match small text sizing by default
+ margin: 0 variables.$db-spacing-fixed-2xs; // small horizontal spacing
+ }
+
+ // Medium size variant
+ &[data-size="medium"] {
+ .db-breadcrumb-list {
+ // Slightly more breathing room for medium size (matches Figma spacing)
+ gap: variables.$db-spacing-fixed-xs; // 8px gap for medium
+
+ /* ensure list items are vertically centered in medium size */
+ align-items: center;
+ }
+
+ li {
+ // Increase gap between separator and item for better touch target
+ gap: variables.$db-spacing-fixed-xs; // 8px between separator and item (medium)
+
+ &:not(:first-child)::before {
+ // Make the chevron larger to match visual weight in Figma
+ inline-size: variables.$db-sizing-lg; // ~24px
+ block-size: variables.$db-sizing-lg;
+ font-size: variables.$db-sizing-lg; // use large sizing token
+ font-weight: 600;
+ color: colors.$db-adaptive-on-bg-basic-emphasis-100-default;
+ }
+
+ a,
+ span {
+ // Keep the medium padding but ensure comfortable tap/click area
+ padding: variables.$db-spacing-fixed-2xs
+ variables.$db-spacing-fixed-xs; // 4px 8px (medium)
+
+ font-size: variables.$db-sizing-md; // 16px (body-md)
+ line-height: variables.$db-sizing-lg; // 24px
+ }
+ }
+ }
+}
diff --git a/packages/components/src/components/breadcrumb/breadcrumb.spec.tsx b/packages/components/src/components/breadcrumb/breadcrumb.spec.tsx
new file mode 100644
index 000000000000..1af69632434d
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/breadcrumb.spec.tsx
@@ -0,0 +1,46 @@
+import AxeBuilder from '@axe-core/playwright';
+import { expect, test } from '@playwright/experimental-ct-react';
+
+import { DBBreadcrumb } from './index';
+// @ts-ignore - vue can only find it with .ts as file ending
+import { DEFAULT_VIEWPORT } from '../../shared/constants.ts';
+
+const defaultBreadcrumb: any = (
+
+
+ Home
+
+
+ Category
+
+ Current Page
+
+);
+
+test.describe('DBBreadcrumb', () => {
+ test('should render', async ({ mount }) => {
+ const component = await mount(defaultBreadcrumb);
+ await expect(component).toBeVisible();
+ });
+
+ test('should have accessible role', async ({ mount }) => {
+ const component = await mount(defaultBreadcrumb);
+ await expect(component).toHaveAttribute('aria-label', 'breadcrumb');
+ });
+
+ test('should not have basic accessibility issues', async ({ mount }) => {
+ const component = await mount(defaultBreadcrumb);
+ const accessibilityScanResults = await new AxeBuilder({
+ page: component.page()
+ })
+ .include('.db-breadcrumb')
+ .analyze();
+ expect(accessibilityScanResults.violations).toEqual([]);
+ });
+
+ test('should match screenshot', async ({ mount }) => {
+ const component = await mount(defaultBreadcrumb);
+ await component.page().setViewportSize(DEFAULT_VIEWPORT);
+ await expect(component).toHaveScreenshot();
+ });
+});
diff --git a/packages/components/src/components/breadcrumb/docs/Angular.md b/packages/components/src/components/breadcrumb/docs/Angular.md
new file mode 100644
index 000000000000..9cee713c86f0
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/docs/Angular.md
@@ -0,0 +1,22 @@
+## Angular
+
+For general installation and configuration take a look at the [ngx-core-components](https://www.npmjs.com/package/@db-ux/ngx-core-components) package.
+
+### Use component
+
+```ts app.component.ts
+// app.component.ts
+import { Component } from "@angular/core";
+
+@Component({
+ selector: "app-root",
+ template: `
+
+ Home
+ Category
+ Current Page
+
+ `
+})
+export class AppComponent {}
+```
diff --git a/packages/components/src/components/breadcrumb/docs/HTML.md b/packages/components/src/components/breadcrumb/docs/HTML.md
new file mode 100644
index 000000000000..f32ee069f5be
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/docs/HTML.md
@@ -0,0 +1,19 @@
+## HTML
+
+### Use component
+
+```html
+
+```
+
+### Import styles
+
+```scss app.scss
+@forward "@db-ux/core-components/build/styles/relative";
+```
diff --git a/packages/components/src/components/breadcrumb/docs/Migration.md b/packages/components/src/components/breadcrumb/docs/Migration.md
new file mode 100644
index 000000000000..c31cf696ec13
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/docs/Migration.md
@@ -0,0 +1,15 @@
+## Migration Guide
+
+### From v2.x to v3.x
+
+Currently no migration needed as this is a new component in v3.x.
+
+### Breaking Changes
+
+- None (new component)
+
+### New Features
+
+- Added `DBBreadcrumb` component for navigation breadcrumbs
+- Supports semantic HTML structure with proper ARIA labels
+- Responsive design with flexbox layout
diff --git a/packages/components/src/components/breadcrumb/docs/React.md b/packages/components/src/components/breadcrumb/docs/React.md
new file mode 100644
index 000000000000..25db6cf87a59
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/docs/React.md
@@ -0,0 +1,24 @@
+## React
+
+For general installation and configuration take a look at the [react-core-components](https://www.npmjs.com/package/@db-ux/react-core-components) package.
+
+### Use component
+
+```tsx App.tsx
+// App.tsx
+import { DBBreadcrumb } from "@db-ux/react-core-components";
+
+const App = () => (
+
+
+ Home
+
+
+ Category
+
+ Current Page
+
+);
+
+export default App;
+```
diff --git a/packages/components/src/components/breadcrumb/docs/Vue.md b/packages/components/src/components/breadcrumb/docs/Vue.md
new file mode 100644
index 000000000000..66655ae86eac
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/docs/Vue.md
@@ -0,0 +1,19 @@
+## Vue
+
+For general installation and configuration take a look at the [v-core-components](https://www.npmjs.com/package/@db-ux/v-core-components) package.
+
+### Use component
+
+```vue App.vue
+
+
+ Home
+ Category
+ Current Page
+
+
+
+
+```
diff --git a/packages/components/src/components/breadcrumb/index.html b/packages/components/src/components/breadcrumb/index.html
new file mode 100644
index 000000000000..afbd1afedfe3
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/index.html
@@ -0,0 +1,30 @@
+
+
+
+
+ DBBreadcrumb
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/src/components/breadcrumb/index.ts b/packages/components/src/components/breadcrumb/index.ts
new file mode 100644
index 000000000000..dbaad9162cf9
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/index.ts
@@ -0,0 +1 @@
+export { default as DBBreadcrumb } from './breadcrumb';
diff --git a/packages/components/src/components/breadcrumb/model.ts b/packages/components/src/components/breadcrumb/model.ts
new file mode 100644
index 000000000000..0a53a0b7bfa5
--- /dev/null
+++ b/packages/components/src/components/breadcrumb/model.ts
@@ -0,0 +1,28 @@
+import { GlobalProps, GlobalState } from '../../shared/model';
+
+export const BreadcrumbSizeList = ['small', 'medium'] as const;
+export type BreadcrumbSize = (typeof BreadcrumbSizeList)[number];
+export const BreadcrumbSeparatorList = ['chevron', 'slash'] as const;
+export type BreadcrumbSeparator = (typeof BreadcrumbSeparatorList)[number];
+
+export interface DBBreadcrumbDefaultProps {
+ /**
+ * The size of the breadcrumb items
+ */
+ size?: BreadcrumbSize;
+
+ /**
+ * The separator between breadcrumb items: 'chevron' or 'slash'
+ */
+ separator?: BreadcrumbSeparator;
+}
+
+export interface DBBreadcrumbProps
+ extends DBBreadcrumbDefaultProps,
+ GlobalProps {}
+
+export interface DBBreadcrumbDefaultState {}
+
+export interface DBBreadcrumbState
+ extends DBBreadcrumbDefaultState,
+ GlobalState {}
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts
index b905eb44af91..b842f70f3076 100644
--- a/packages/components/src/index.ts
+++ b/packages/components/src/index.ts
@@ -6,6 +6,8 @@ export * from './components/badge';
export * from './components/badge/model';
export * from './components/brand';
export * from './components/brand/model';
+export * from './components/breadcrumb';
+export * from './components/breadcrumb/model';
export * from './components/button';
export * from './components/button/model';
export * from './components/card';
diff --git a/packages/components/src/styles/index.scss b/packages/components/src/styles/index.scss
index 0830302f8b04..47cf969698b2 100644
--- a/packages/components/src/styles/index.scss
+++ b/packages/components/src/styles/index.scss
@@ -5,6 +5,7 @@
@forward "../components/card/card";
@forward "../components/input/input";
@forward "../components/brand/brand";
+@forward "../components/breadcrumb/breadcrumb";
@forward "../components/header/header";
@forward "../components/page/page";
@forward "../components/link/link";
diff --git a/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.html b/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.html
new file mode 100644
index 000000000000..76bc16b150c0
--- /dev/null
+++ b/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
diff --git a/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.ts b/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.ts
new file mode 100644
index 000000000000..c847af745c39
--- /dev/null
+++ b/showcases/angular-showcase/src/app/components/breadcrumb/breadcrumb.component.ts
@@ -0,0 +1,15 @@
+import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+// TODO: Uncomment after build-outputs: import { DBBreadcrumb } from '../../../../../../output/angular/src';
+import defaultComponentVariants from '../../../../../shared/breadcrumb.json';
+import { DefaultComponent } from '../default.component';
+
+@Component({
+ selector: 'app-breadcrumb',
+ templateUrl: './breadcrumb.component.html',
+ imports: [DefaultComponent],
+ standalone: true,
+ schemas: [CUSTOM_ELEMENTS_SCHEMA]
+})
+export class BreadcrumbComponent {
+ variants = defaultComponentVariants;
+}
diff --git a/showcases/angular-showcase/src/app/utils/navigation-item.ts b/showcases/angular-showcase/src/app/utils/navigation-item.ts
index b7b06efdd447..718c4a70fd51 100644
--- a/showcases/angular-showcase/src/app/utils/navigation-item.ts
+++ b/showcases/angular-showcase/src/app/utils/navigation-item.ts
@@ -3,6 +3,7 @@ import { AccordionItemComponent } from '../components/accordion-item/accordion-i
import { AccordionComponent } from '../components/accordion/accordion.component';
import { BadgeComponent } from '../components/badge/badge.component';
import { BrandComponent } from '../components/brand/brand.component';
+import { BreadcrumbComponent } from '../components/breadcrumb/breadcrumb.component';
import { ButtonComponent } from '../components/button/button.component';
import { CardComponent } from '../components/card/card.component';
import { CheckboxComponent } from '../components/checkbox/checkbox.component';
@@ -60,6 +61,11 @@ export const NAVIGATION_ITEMS: NavItem[] = [
path: '05',
label: '05 Navigation',
subNavigation: getSortedNavigationItems([
+ {
+ path: '05/breadcrumb',
+ label: 'Breadcrumb',
+ component: BreadcrumbComponent
+ },
{
path: '05/navigation-item',
label: 'NavigationItem',
diff --git a/showcases/e2e/breadcrumb/breadcrumb-a11y-checker.spec.ts b/showcases/e2e/breadcrumb/breadcrumb-a11y-checker.spec.ts
new file mode 100644
index 000000000000..826ae6a20316
--- /dev/null
+++ b/showcases/e2e/breadcrumb/breadcrumb-a11y-checker.spec.ts
@@ -0,0 +1,6 @@
+import { test } from '@playwright/test';
+import { runA11yCheckerTest } from '../default.ts';
+
+test.describe('DBBreadcrumb', () => {
+ runA11yCheckerTest({ path: '05/breadcrumb' });
+});
diff --git a/showcases/e2e/breadcrumb/breadcrumb-aria-snapshot.spec.ts b/showcases/e2e/breadcrumb/breadcrumb-aria-snapshot.spec.ts
new file mode 100644
index 000000000000..dd90e6c03396
--- /dev/null
+++ b/showcases/e2e/breadcrumb/breadcrumb-aria-snapshot.spec.ts
@@ -0,0 +1,6 @@
+import { test } from '@playwright/test';
+import { runAriaSnapshotTest } from '../default.ts';
+
+test.describe('DBBreadcrumb', () => {
+ runAriaSnapshotTest({ path: '05/breadcrumb' });
+});
diff --git a/showcases/e2e/breadcrumb/breadcrumb-axe-core.spec.ts b/showcases/e2e/breadcrumb/breadcrumb-axe-core.spec.ts
new file mode 100644
index 000000000000..7d7da93e1b31
--- /dev/null
+++ b/showcases/e2e/breadcrumb/breadcrumb-axe-core.spec.ts
@@ -0,0 +1,9 @@
+import { test } from '@playwright/test';
+import { runAxeCoreTest } from '../default.ts';
+import { lvl3 } from '../fixtures/variants';
+
+test.describe('DBBreadcrumb', () => {
+ runAxeCoreTest({ path: '05/breadcrumb' });
+ runAxeCoreTest({ path: '05/breadcrumb', color: lvl3 });
+ runAxeCoreTest({ path: '05/breadcrumb', density: 'functional' });
+});
diff --git a/showcases/e2e/breadcrumb/breadcrumb-visual-snapshot.spec.ts b/showcases/e2e/breadcrumb/breadcrumb-visual-snapshot.spec.ts
new file mode 100644
index 000000000000..1324a7edc3dd
--- /dev/null
+++ b/showcases/e2e/breadcrumb/breadcrumb-visual-snapshot.spec.ts
@@ -0,0 +1,7 @@
+import { test } from '@playwright/test';
+import { getDefaultScreenshotTest } from '../default.ts';
+
+const path = '05/breadcrumb';
+test.describe('DBBreadcrumb', () => {
+ getDefaultScreenshotTest({ path });
+});
diff --git a/showcases/react-showcase/src/components/breadcrumb/index.tsx b/showcases/react-showcase/src/components/breadcrumb/index.tsx
new file mode 100644
index 000000000000..5f5c6f8a04f6
--- /dev/null
+++ b/showcases/react-showcase/src/components/breadcrumb/index.tsx
@@ -0,0 +1,56 @@
+import { DBBreadcrumb } from '../../../../../output/react/src';
+import defaultComponentVariants from '../../../../shared/breadcrumb.json';
+import { getVariants } from '../data';
+import DefaultComponent from '../default-component';
+
+type BreadcrumbItem = {
+ href?: string;
+ text: string;
+ ariaCurrent?: 'page' | undefined;
+};
+
+type BreadcrumbExampleProps = {
+ children?: BreadcrumbItem[];
+ size?: 'small' | 'medium';
+ className?: string;
+ separator?: 'chevron' | 'slash';
+};
+
+const getBreadcrumb = ({
+ children,
+ size,
+ className,
+ separator
+}: BreadcrumbExampleProps) => (
+
+ {children && Array.isArray(children)
+ ? children.map((item, index) =>
+ item.href ? (
+
+ {item.text}
+
+ ) : (
+
+ {item.text}
+
+ )
+ )
+ : children}
+
+);
+
+type BreadcrumbComponentProps = {
+ slotCode?: Record;
+};
+
+const BreadcrumbComponent = (props: BreadcrumbComponentProps) => (
+
+);
+
+export default BreadcrumbComponent;
diff --git a/showcases/react-showcase/src/components/data.ts b/showcases/react-showcase/src/components/data.ts
index cd1333254ce9..4e774471b786 100644
--- a/showcases/react-showcase/src/components/data.ts
+++ b/showcases/react-showcase/src/components/data.ts
@@ -14,6 +14,8 @@ export const getVariants = (
],
examples: variant.examples.map((example, exampleIndex) => ({
...example,
+ // Ensure className from props is available on the example object
+ className: example.className ?? example.props?.className,
example: getExample({
...example.props,
id: example.props?.id ?? example.name,
diff --git a/showcases/react-showcase/src/utils/navigation-item.tsx b/showcases/react-showcase/src/utils/navigation-item.tsx
index 1f5f0774bb6e..6797ac7b1b22 100644
--- a/showcases/react-showcase/src/utils/navigation-item.tsx
+++ b/showcases/react-showcase/src/utils/navigation-item.tsx
@@ -2,6 +2,7 @@ import AccordionComponent from '../components/accordion';
import AccordionItemComponent from '../components/accordion-item';
import BadgeComponent from '../components/badge';
import BrandComponent from '../components/brand';
+import BreadcrumbComponent from '../components/breadcrumb';
import ButtonComponent from '../components/button';
import CardComponent from '../components/card';
import CheckboxComponent from '../components/checkbox';
@@ -60,6 +61,11 @@ export const NAVIGATION_ITEMS: NavigationItem[] = [
path: '05',
label: '05 Navigation',
subNavigation: getSortedNavigationItems([
+ {
+ path: 'breadcrumb',
+ label: 'Breadcrumb',
+ component:
+ },
{
path: 'navigation-item',
label: 'NavigationItem',
diff --git a/showcases/shared/breadcrumb.json b/showcases/shared/breadcrumb.json
new file mode 100644
index 000000000000..d603323c3c44
--- /dev/null
+++ b/showcases/shared/breadcrumb.json
@@ -0,0 +1,60 @@
+[
+ {
+ "name": "Size",
+ "examples": [
+ {
+ "name": "(Default) Small",
+ "className": "w-full",
+ "props": {
+ "size": "small",
+ "children": [
+ { "href": "#", "text": "Home" },
+ { "href": "#", "text": "Category" },
+ { "text": "Current Page", "ariaCurrent": "page" }
+ ]
+ }
+ },
+ {
+ "name": "Medium",
+ "className": "w-full",
+ "props": {
+ "size": "medium",
+ "children": [
+ { "href": "#", "text": "Home" },
+ { "href": "#", "text": "Category" },
+ { "text": "Current Page", "ariaCurrent": "page" }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "Separator",
+ "examples": [
+ {
+ "name": "Chevron",
+ "className": "w-full",
+ "props": {
+ "separator": "chevron",
+ "children": [
+ { "href": "#", "text": "Home" },
+ { "href": "#", "text": "Category" },
+ { "text": "Current Page", "ariaCurrent": "page" }
+ ]
+ }
+ },
+ {
+ "name": "Slash",
+ "className": "w-full",
+ "props": {
+ "separator": "slash",
+ "children": [
+ { "href": "#", "text": "Home" },
+ { "href": "#", "text": "Category" },
+ { "text": "Current Page", "ariaCurrent": "page" }
+ ]
+ }
+ }
+ ]
+ }
+]
diff --git a/showcases/showcase-styles.css b/showcases/showcase-styles.css
index b244b174a8f8..dc3c89cacc5a 100644
--- a/showcases/showcase-styles.css
+++ b/showcases/showcase-styles.css
@@ -67,6 +67,18 @@ db-card:is(.variants-card) > .db-card {
margin-block: 0 auto;
}
+/* Breadcrumb showcase: stack breadcrumb examples vertically */
+@supports selector(:has(*)) {
+ .variants-list > div:has(.db-breadcrumb) {
+ flex: 0 0 100%;
+ }
+}
+
+/* Fallback: if :has unsupported, rely on utility class or force wrappers containing db-breadcrumb to behave as block via descendant width trick */
+.variants-list .db-breadcrumb {
+ inline-size: 100%;
+}
+
.html-code-container {
display: flex;
flex-direction: column;
diff --git a/showcases/vue-showcase/src/components/breadcrumb/breadcrumb.vue b/showcases/vue-showcase/src/components/breadcrumb/breadcrumb.vue
new file mode 100644
index 000000000000..3782b50d8210
--- /dev/null
+++ b/showcases/vue-showcase/src/components/breadcrumb/breadcrumb.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+ -
+ {{
+ item.text
+ }}
+ {{ item.text }}
+
+
+
+
+
+
diff --git a/showcases/vue-showcase/src/utils/navigation-items.ts b/showcases/vue-showcase/src/utils/navigation-items.ts
index beee8433a446..a4fb5ae25ef5 100644
--- a/showcases/vue-showcase/src/utils/navigation-items.ts
+++ b/showcases/vue-showcase/src/utils/navigation-items.ts
@@ -4,6 +4,7 @@ import AccordionItem from '../components/accordion-item/AccordionItem.vue';
import Accordion from '../components/accordion/Accordion.vue';
import Badge from '../components/badge/Badge.vue';
import Brand from '../components/brand/Brand.vue';
+import Breadcrumb from '../components/breadcrumb/breadcrumb.vue';
import Button from '../components/button/Button.vue';
import Card from '../components/card/Card.vue';
import Checkbox from '../components/checkbox/Checkbox.vue';
@@ -61,6 +62,11 @@ export const navigationItems: NavItem[] = [
path: '/05',
label: '05 Navigation',
subNavigation: getSortedNavigationItems([
+ {
+ path: '/05/breadcrumb',
+ label: 'Breadcrumb',
+ component: markRaw(Breadcrumb)
+ },
{
path: '/05/navigation-item',
label: 'NavigationItem',