diff --git a/continue.md b/continue.md
index 852193934..18b56fce0 100644
--- a/continue.md
+++ b/continue.md
@@ -21,11 +21,11 @@ Fecha de corte: 2026-05-17. Rama: `active-uix`.
- `rating-group`
- `search-field`
- `number-field`
+ - `breadcrumb`
- Siguiente decision antes de seguir migrando:
- Continuar con componentes de riesgo bajo/medio (`field`, `toolbar`,
- `breadcrumb`, `tag-group`) o parar a definir una tabla de migracion por
- componente para los grandes (`select`, `combobox`, `calendar`,
- `date-field`).
+ `tag-group`) o parar a definir una tabla de migracion por componente para
+ los grandes (`select`, `combobox`, `calendar`, `date-field`).
- Para cada componente nuevo conviene escribir primero: partes Soma,
props visuales Eidos, `data-*` que estampa el wrapper, tokens de recipe y
attrs morfo-backed que consumira el CSS.
@@ -122,9 +122,22 @@ Actualizacion Eidos component migration 2026-05-17:
- `npm run check` -> 0 errores, 0 warnings.
- `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift
hotspots.
+- Septima tanda del mismo bloque:
+ - `Breadcrumb`: root visual `breadcrumb.svelte`, partes `List`, `Item`,
+ `Link`, `Separator`, `Ellipsis`, `breadcrumb.css`, `types.ts` e `index.ts`.
+ - El wrapper conserva semantica, current item/link, ellipsis interactivo y
+ ARIA de Soma; Eidos solo anade `size`.
+ - La receta consume `data-current` y `data-interactive` declarados por Morfo
+ y define tokens para gaps, tipografia, links, separador, ellipsis, foco y
+ transiciones.
+- Validado despues de `Breadcrumb`:
+ - `npx vitest run src/uix/eidos` -> 7 archivos, 84 tests OK.
+ - `npm run check` -> 0 errores, 0 warnings.
+ - `node --import tsx/esm scripts/eidos-lint-all.ts` -> 0 invalid, sin drift
+ hotspots.
- Siguiente bloque sugerido:
- Migrar otro grupo de bajo riesgo desde Soma a Eidos: candidatos reales por
- morfo/soma existentes son `field`, `toolbar`, `breadcrumb` o `tag-group`.
+ morfo/soma existentes son `field`, `toolbar` o `tag-group`.
- Antes de tocar componentes grandes (`select`, `combobox`, `calendar`,
`date-field`) conviene fijar una tabla por componente: partes Soma,
props visuales Eidos, recipe tokens y attrs esperados.
diff --git a/src/uix/README.md b/src/uix/README.md
index 6541fbd9c..bc40fc17f 100644
--- a/src/uix/README.md
+++ b/src/uix/README.md
@@ -162,8 +162,8 @@ leer CSS.
La migración de componentes Soma -> Eidos se retoma por tandas pequeñas. A fecha
2026-05-17, además de los pilotos previos, ya están migrados `meter`,
`progress`, `slider`, `pagination`, `rating-group`, `search-field` y
-`number-field`; cada uno envuelve partes públicas de Soma y añade únicamente
-superficie visual.
+`number-field`, y `breadcrumb`; cada uno envuelve partes públicas de Soma y
+añade únicamente superficie visual.
Eidos lee del DOM lo que las otras capas escriben (parts, data-attrs, ARIA,
event signals) — nunca importa internals de soma ni de sema.
diff --git a/src/uix/active_architecture.md b/src/uix/active_architecture.md
index d01925fd2..d7f1c938b 100644
--- a/src/uix/active_architecture.md
+++ b/src/uix/active_architecture.md
@@ -881,7 +881,7 @@ Para evitar mission creep, conviene fijar lo que UIX **no quiere ser**:
La tanda de wrappers migrados desde Soma queda documentada en
`eidos/components/README.md`; a fecha 2026-05-17 incluye primitives de estado
y formulario como `progress`, `meter`, `slider`, `pagination`,
- `rating-group`, `search-field` y `number-field`.
+ `rating-group`, `search-field`, `number-field` y `breadcrumb`.
- `adom` — `dom.apply(change)`, `dom.remove(target, names)`. Toda la
superficie reactiva (viewport, breakpoints, listeners, observers,
BodyScrollLock, DOMContext, RovingFocusGroup) ya estable.
diff --git a/src/uix/eidos/README.md b/src/uix/eidos/README.md
index 5d41233c8..83d3948f4 100644
--- a/src/uix/eidos/README.md
+++ b/src/uix/eidos/README.md
@@ -695,8 +695,8 @@ podrá retirarse.
`toggle`, `switch`, `collapsible`, `dialog`, `drawer`, `popover`, `toast`,
`accordion`, `avatar`, `tooltip`, `tabs`, `checkbox`, `radio-group`,
`meter`, `progress`, `slider`, `pagination`, `rating-group`,
- `search-field` y `number-field`. Todos usan root visual + partes attached,
- sin `Provider` público ni API flat.
+ `search-field`, `number-field` y `breadcrumb`. Todos usan root visual +
+ partes attached, sin `Provider` público ni API flat.
- **Color**: basado en roles canonicos de jerarquia e intents
(`primary`, `secondary`, `tertiary`, `neutral`, `affirm`, `fulfill`,
`risk`, `threat`, `loss`) y escalas de 12 pasos. Por cada escala genera
diff --git a/src/uix/eidos/component-visual-attrs.test.ts b/src/uix/eidos/component-visual-attrs.test.ts
index 7605aae4e..8bf300887 100644
--- a/src/uix/eidos/component-visual-attrs.test.ts
+++ b/src/uix/eidos/component-visual-attrs.test.ts
@@ -10,6 +10,7 @@ const VISUAL_ATTRS = [
['accordion/accordion-header.svelte', ['data-size']],
['accordion/accordion-trigger.svelte', ['data-size', 'data-indicator-placement']],
['avatar/avatar.svelte', ['data-size', 'data-variant', 'data-color']],
+ ['breadcrumb/breadcrumb.svelte', ['data-size']],
['checkbox/checkbox.svelte', ['data-size', 'data-variant', 'data-color']],
['checkbox/checkbox-group.svelte', ['data-columns']],
['dialog/dialog-close.svelte', ['data-position', 'data-icon-only']],
diff --git a/src/uix/eidos/components/README.md b/src/uix/eidos/components/README.md
index 3d66ab447..81b097f44 100644
--- a/src/uix/eidos/components/README.md
+++ b/src/uix/eidos/components/README.md
@@ -358,6 +358,7 @@ estado, ARIA, traducciones y escritura headless en Soma/Morfo.
| toast | ✅ multi-part | + Toaster separate |
| accordion | ✅ multi-part | Item, Header, Trigger, Content |
| avatar | ✅ multi-part | Image, Fallback (eidos-native) |
+| breadcrumb | ✅ multi-part | List, Item, Link, Separator, Ellipsis |
| icon | ✅ single-part | + 1697 lucide glyphs |
| meter | ✅ multi-part | Indicator |
| number-field | ✅ multi-part | Input, IncrementTrigger, DecrementTrigger, Scrubber |
@@ -374,7 +375,7 @@ estado, ARIA, traducciones y escritura headless en Soma/Morfo.
### Orden recomendado para continuar
1. Componentes simples de composición/formulario: `field`, `toolbar`,
- `breadcrumb`, `tag-group`.
+ `tag-group`.
2. Componentes medianos con más partes o layout interno: `file-upload`,
`tags-input`, `editable`, `stepper`.
3. Componentes grandes sólo con tabla previa de migración: `select`,
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb-ellipsis.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb-ellipsis.svelte
new file mode 100644
index 000000000..f2b319ddc
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb-ellipsis.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb-item.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb-item.svelte
new file mode 100644
index 000000000..fded90597
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb-item.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb-link.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb-link.svelte
new file mode 100644
index 000000000..25a9ba772
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb-link.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb-list.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb-list.svelte
new file mode 100644
index 000000000..8f34633a6
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb-list.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb-separator.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb-separator.svelte
new file mode 100644
index 000000000..8c55574cb
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb-separator.svelte
@@ -0,0 +1,10 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb.css b/src/uix/eidos/components/breadcrumb/breadcrumb.css
new file mode 100644
index 000000000..6425c7ba4
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb.css
@@ -0,0 +1,110 @@
+[data-breadcrumb] {
+ --_breadcrumb-gap: var(--breadcrumb-gap-md);
+ --_breadcrumb-font-size: var(--breadcrumb-font-size-md);
+
+ color: var(--breadcrumb-color);
+ font-family: var(--breadcrumb-font-family);
+ font-size: var(--_breadcrumb-font-size);
+ line-height: var(--breadcrumb-line-height);
+}
+
+[data-breadcrumb][data-size='sm'] {
+ --_breadcrumb-gap: var(--breadcrumb-gap-sm);
+ --_breadcrumb-font-size: var(--breadcrumb-font-size-sm);
+}
+
+[data-breadcrumb][data-size='lg'] {
+ --_breadcrumb-gap: var(--breadcrumb-gap-lg);
+ --_breadcrumb-font-size: var(--breadcrumb-font-size-lg);
+}
+
+[data-breadcrumb-list] {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: var(--_breadcrumb-gap);
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+[data-breadcrumb-item],
+[data-breadcrumb-separator] {
+ display: inline-flex;
+ align-items: center;
+ min-inline-size: 0;
+}
+
+[data-breadcrumb-link] {
+ display: inline-flex;
+ align-items: center;
+ min-inline-size: 0;
+ border-radius: var(--breadcrumb-link-radius);
+ color: var(--breadcrumb-link-color);
+ font-weight: var(--breadcrumb-link-font-weight);
+ text-decoration: none;
+ outline: none;
+ transition:
+ color var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease),
+ box-shadow var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease);
+}
+
+[data-breadcrumb-link]:hover:not([data-current]) {
+ color: var(--breadcrumb-link-color-hover);
+}
+
+[data-breadcrumb-link]:focus-visible {
+ box-shadow: var(--breadcrumb-focus-shadow);
+}
+
+[data-breadcrumb-link][data-current] {
+ color: var(--breadcrumb-link-color-current);
+ font-weight: var(--breadcrumb-link-font-weight-current);
+ cursor: default;
+}
+
+[data-breadcrumb-separator] {
+ color: var(--breadcrumb-separator-color);
+ user-select: none;
+}
+
+[data-breadcrumb-ellipsis] {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-inline-size: var(--breadcrumb-ellipsis-size);
+ block-size: var(--breadcrumb-ellipsis-size);
+ border: var(--breadcrumb-ellipsis-border-width) solid var(--breadcrumb-ellipsis-border);
+ border-radius: var(--breadcrumb-ellipsis-radius);
+ background: var(--breadcrumb-ellipsis-bg);
+ color: var(--breadcrumb-ellipsis-color);
+ font: inherit;
+ outline: none;
+ user-select: none;
+}
+
+[data-breadcrumb-ellipsis][data-interactive] {
+ cursor: pointer;
+ transition:
+ background var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease),
+ border-color var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease),
+ color var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease),
+ box-shadow var(--breadcrumb-transition-duration) var(--breadcrumb-transition-ease);
+}
+
+[data-breadcrumb-ellipsis][data-interactive]:hover {
+ border-color: var(--breadcrumb-ellipsis-border-hover);
+ background: var(--breadcrumb-ellipsis-bg-hover);
+ color: var(--breadcrumb-ellipsis-color-hover);
+}
+
+[data-breadcrumb-ellipsis][data-interactive]:focus-visible {
+ box-shadow: var(--breadcrumb-focus-shadow);
+}
+
+@media (prefers-reduced-motion: reduce) {
+ [data-breadcrumb-link],
+ [data-breadcrumb-ellipsis][data-interactive] {
+ transition: none;
+ }
+}
diff --git a/src/uix/eidos/components/breadcrumb/breadcrumb.svelte b/src/uix/eidos/components/breadcrumb/breadcrumb.svelte
new file mode 100644
index 000000000..5a27e0258
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/breadcrumb.svelte
@@ -0,0 +1,18 @@
+
+
+
+ {@render children?.()}
+
diff --git a/src/uix/eidos/components/breadcrumb/index.ts b/src/uix/eidos/components/breadcrumb/index.ts
new file mode 100644
index 000000000..fde5fae4d
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/index.ts
@@ -0,0 +1,47 @@
+// Breadcrumb — eidos compound API, disciplined option C.
+//
+// import { Breadcrumb } from '$uix/eidos/components/breadcrumb';
+//
+//
+//
+// Home
+//
+// Docs
+//
+//
+import BreadcrumbRoot from './breadcrumb.svelte';
+import List from './breadcrumb-list.svelte';
+import Item from './breadcrumb-item.svelte';
+import Link from './breadcrumb-link.svelte';
+import Separator from './breadcrumb-separator.svelte';
+import Ellipsis from './breadcrumb-ellipsis.svelte';
+
+type BreadcrumbNamespace = typeof BreadcrumbRoot & {
+ List: typeof List;
+ Item: typeof Item;
+ Link: typeof Link;
+ Separator: typeof Separator;
+ Ellipsis: typeof Ellipsis;
+};
+
+const Breadcrumb = BreadcrumbRoot as BreadcrumbNamespace;
+Breadcrumb.List = List;
+Breadcrumb.Item = Item;
+Breadcrumb.Link = Link;
+Breadcrumb.Separator = Separator;
+Breadcrumb.Ellipsis = Ellipsis;
+
+export { Breadcrumb };
+
+export default Breadcrumb;
+
+export type {
+ BreadcrumbCurrent,
+ BreadcrumbProps,
+ BreadcrumbListProps as ListProps,
+ BreadcrumbItemProps as ItemProps,
+ BreadcrumbLinkProps as LinkProps,
+ BreadcrumbSeparatorProps as SeparatorProps,
+ BreadcrumbEllipsisProps as EllipsisProps,
+ BreadcrumbSize
+} from './types';
diff --git a/src/uix/eidos/components/breadcrumb/types.ts b/src/uix/eidos/components/breadcrumb/types.ts
new file mode 100644
index 000000000..12a148427
--- /dev/null
+++ b/src/uix/eidos/components/breadcrumb/types.ts
@@ -0,0 +1,30 @@
+import type {
+ BreadcrumbCurrent,
+ EllipsisProps as SomaBreadcrumbEllipsisProps,
+ ItemProps as SomaBreadcrumbItemProps,
+ LinkProps as SomaBreadcrumbLinkProps,
+ ListProps as SomaBreadcrumbListProps,
+ ProviderProps as SomaBreadcrumbProviderProps,
+ SeparatorProps as SomaBreadcrumbSeparatorProps
+} from '$soma/components/breadcrumb';
+import type { ResponsiveProp, Size } from '$uix/eidos/lib/types';
+
+export type BreadcrumbSize = Extract;
+
+/**
+ * Props for the eidos ``.
+ *
+ * Extends Soma's breadcrumb landmark with visual sizing only. Current crumb,
+ * ARIA label/current and interactive ellipsis semantics are owned by Soma.
+ */
+export type BreadcrumbProps = SomaBreadcrumbProviderProps & {
+ /** Visual size. Accepts a responsive map resolved by ActiveEidos. @default 'md' */
+ size?: ResponsiveProp;
+};
+
+export type BreadcrumbListProps = SomaBreadcrumbListProps;
+export type BreadcrumbItemProps = SomaBreadcrumbItemProps;
+export type BreadcrumbLinkProps = SomaBreadcrumbLinkProps;
+export type BreadcrumbSeparatorProps = SomaBreadcrumbSeparatorProps;
+export type BreadcrumbEllipsisProps = SomaBreadcrumbEllipsisProps;
+export type { BreadcrumbCurrent };
diff --git a/src/uix/eidos/generated/base.css b/src/uix/eidos/generated/base.css
index 8d49d9fab..4390dc8df 100644
--- a/src/uix/eidos/generated/base.css
+++ b/src/uix/eidos/generated/base.css
@@ -415,6 +415,34 @@
--avatar-color-loss-soft-fg: var(--color-loss-text);
--avatar-color-loss-outline-border: var(--color-loss-border);
--avatar-color-loss-outline-fg: var(--color-loss-text);
+ --breadcrumb-gap-sm: var(--space-1);
+ --breadcrumb-gap-md: var(--space-1-5);
+ --breadcrumb-gap-lg: var(--space-2);
+ --breadcrumb-font-family: var(--font-ui);
+ --breadcrumb-font-size-sm: var(--font-size-xs);
+ --breadcrumb-font-size-md: var(--font-size-sm);
+ --breadcrumb-font-size-lg: var(--font-size-sm);
+ --breadcrumb-line-height: var(--leading-ui);
+ --breadcrumb-color: var(--color-content-secondary);
+ --breadcrumb-link-radius: var(--radius-sm);
+ --breadcrumb-link-color: var(--color-content-secondary);
+ --breadcrumb-link-color-hover: var(--color-content-primary);
+ --breadcrumb-link-color-current: var(--color-content-primary);
+ --breadcrumb-link-font-weight: var(--font-weight-medium);
+ --breadcrumb-link-font-weight-current: var(--font-weight-semibold);
+ --breadcrumb-separator-color: var(--color-content-muted);
+ --breadcrumb-ellipsis-size: var(--control-height-xs);
+ --breadcrumb-ellipsis-radius: var(--radius-md);
+ --breadcrumb-ellipsis-border-width: var(--border-width);
+ --breadcrumb-ellipsis-border: transparent;
+ --breadcrumb-ellipsis-border-hover: var(--color-border-subtle);
+ --breadcrumb-ellipsis-bg: transparent;
+ --breadcrumb-ellipsis-bg-hover: var(--color-surface-raised);
+ --breadcrumb-ellipsis-color: var(--color-content-muted);
+ --breadcrumb-ellipsis-color-hover: var(--color-content-primary);
+ --breadcrumb-focus-shadow: 0 0 0 var(--focus-ring-offset) var(--color-surface-default), 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color);
+ --breadcrumb-transition-duration: var(--duration-fast);
+ --breadcrumb-transition-ease: var(--ease-default);
--checkbox-size-sm-box-size: 16px;
--checkbox-size-sm-indicator-size: 10px;
--checkbox-size-sm-indicator-stroke: 2px;
diff --git a/src/uix/eidos/index.css b/src/uix/eidos/index.css
index 49fb518ac..ebe769663 100644
--- a/src/uix/eidos/index.css
+++ b/src/uix/eidos/index.css
@@ -62,6 +62,7 @@
/* ── Component recipes ──────────────────────────────────────────────────── */
@import './components/icon/icon.css';
@import './components/avatar/avatar.css';
+@import './components/breadcrumb/breadcrumb.css';
@import './components/toast/toast.css';
@import './components/dialog/dialog.css';
@import './components/drawer/drawer.css';
diff --git a/src/uix/eidos/lib/recipes/base.ts b/src/uix/eidos/lib/recipes/base.ts
index 8880a8c6e..311157d3c 100644
--- a/src/uix/eidos/lib/recipes/base.ts
+++ b/src/uix/eidos/lib/recipes/base.ts
@@ -142,6 +142,37 @@ export const THEME_BASE_RECIPE_TOKENS = {
'color-loss-outline-border': 'var(--color-loss-border)',
'color-loss-outline-fg': 'var(--color-loss-text)'
},
+ breadcrumb: {
+ 'gap-sm': 'var(--space-1)',
+ 'gap-md': 'var(--space-1-5)',
+ 'gap-lg': 'var(--space-2)',
+ 'font-family': 'var(--font-ui)',
+ 'font-size-sm': 'var(--font-size-xs)',
+ 'font-size-md': 'var(--font-size-sm)',
+ 'font-size-lg': 'var(--font-size-sm)',
+ 'line-height': 'var(--leading-ui)',
+ color: 'var(--color-content-secondary)',
+ 'link-radius': 'var(--radius-sm)',
+ 'link-color': 'var(--color-content-secondary)',
+ 'link-color-hover': 'var(--color-content-primary)',
+ 'link-color-current': 'var(--color-content-primary)',
+ 'link-font-weight': 'var(--font-weight-medium)',
+ 'link-font-weight-current': 'var(--font-weight-semibold)',
+ 'separator-color': 'var(--color-content-muted)',
+ 'ellipsis-size': 'var(--control-height-xs)',
+ 'ellipsis-radius': 'var(--radius-md)',
+ 'ellipsis-border-width': 'var(--border-width)',
+ 'ellipsis-border': 'transparent',
+ 'ellipsis-border-hover': 'var(--color-border-subtle)',
+ 'ellipsis-bg': 'transparent',
+ 'ellipsis-bg-hover': 'var(--color-surface-raised)',
+ 'ellipsis-color': 'var(--color-content-muted)',
+ 'ellipsis-color-hover': 'var(--color-content-primary)',
+ 'focus-shadow':
+ '0 0 0 var(--focus-ring-offset) var(--color-surface-default), 0 0 0 calc(var(--focus-ring-offset) + var(--focus-ring-width)) var(--focus-ring-color)',
+ 'transition-duration': 'var(--duration-fast)',
+ 'transition-ease': 'var(--ease-default)'
+ },
checkbox: {
'size-sm-box-size': '16px',
'size-sm-indicator-size': '10px',