Breadcrumb Ellipsis
Use breadcrumbEllipsis on a <button> element to represent collapsed items in a breadcrumb trail. It renders an accessible trigger (aria-label "More breadcrumb items") with hover and focus-visible states. Typically placed inside a breadcrumb nav alongside link items.
| Prop | Type | Default | Description |
|---|---|---|---|
color | ValueOrState<ThemeColor> | "neutral" | Color tone for the trigger text and hover/focus states. |
Customization
Must see the source of patch at the bottom of each patch page to understand the structure then code it still code as html native element.
There are four levels of customization, in increasing order of effort:
- Patch props. Each patch exposes a small, stable set of props—typically fewer than five. Lowest friction.
- Context attributes. Use
dataTone,dataSize, anddataDensityon a container to shift tone, size, or density for an entire subtree without touching individual elements. - Inline override. Native-wins merge strategy: any property set directly on the element overrides the patch value.
- Create a variant. Clone a similar patch and edit it. Use this only when you need a reusable custom version.
Formulas
Unit - U = fontSize / 4 - convert final values with themeSpacing(n).
Size - n = intrinsic text lines, w = wrapping level, d = density factor:
height = (n * 6 + 2 * d * w) * U
paddingBlock = d * w * U
paddingInline = ceil(3 / w) * d * w * U
radius = d * w * U
Base density d = 1.5:
| U | w=0 | w=1 | w=2 | w=3 |
|---|---|---|---|---|
height (n = 1) | 6 | 9 | 12 | 15 |
| paddingBlock | 0 | 1.5 | 3 | 4.5 |
| paddingInline | 3 | 4.5 | 6 | 4.5 |
| radius | 0 | 1.5 | 3 | 4.5 |
Tone - K = N / 2 where N is the palette length. For N = 18, K = 9.
| Role | Shift | n=0 |
|---|---|---|
| Background | parent +/- n | 0 |
| Text | bg + K | 6 |
| Border | bg + K/2 | 3 |
| Hover | bg + 2K/3 | 4 |
| Selected / Focus | above +/- K/3 | 2-4 |
State shift range: K/3 <= delta <= 2K/3.
<div class="blocks">
<div class="block active" data-tab="0">
import type { PartialElement } from "@domphy/core";
import { toState, type ValueOrState } from "@domphy/core";
import {
type ThemeColor,
themeColor,
themeSize,
themeSpacing,
} from "@domphy/theme";
/**
* An ellipsis trigger button for collapsed breadcrumb items, with hover and
* focus-visible states. Apply to a `<button>` element.
*
* @hostTag button
* @param props.color - Color tone for the trigger. Optional `ValueOrState<ThemeColor>`, default "neutral".
* @example { button: "…", $: [breadcrumbEllipsis({ color: "neutral" })] }
*/
function breadcrumbEllipsis(
props: { color?: ValueOrState<ThemeColor> } = {},
): PartialElement {
const color = toState(props.color ?? "neutral", "color");
return {
_onInsert: (node) => {
if (node.tagName !== "button") {
console.warn('"breadcrumbEllipsis" patch must use button tag');
}
},
ariaLabel: "More breadcrumb items",
style: {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
fontSize: (listener) => themeSize(listener, "inherit"),
paddingInline: themeSpacing(1),
border: "none",
background: "none",
cursor: "pointer",
color: (listener) => themeColor(listener, "shift-8", color.get(listener)),
borderRadius: themeSpacing(1),
"&:hover": {
color: (listener) =>
themeColor(listener, "shift-10", color.get(listener)),
backgroundColor: (listener) =>
themeColor(listener, "shift-2", color.get(listener)),
},
"&:focus-visible": {
outline: (listener) =>
`${themeSpacing(0.5)} solid ${themeColor(listener, "shift-6", color.get(listener))}`,
outlineOffset: themeSpacing(0.5),
},
},
};
}
export { breadcrumbEllipsis };
</div>
<div class="block" data-tab="1">
import type { PartialElement } from "@domphy/core";
import { toState, type ValueOrState } from "@domphy/core";
import {
type ThemeColor,
themeColor,
themeSize,
themeSpacing,
} from "@domphy/theme";
/**
* A horizontal breadcrumb navigation that lays out its children with a
* separator between items and highlights the `[aria-current=page]` item.
* Apply to a `<nav>` element.
*
* @hostTag nav
* @param props.color - Color tone for links/separators. Optional `ValueOrState<ThemeColor>`, default "neutral".
* @param props.separator - String inserted between items via `::after`. Optional `string`, default "/".
* @example { nav: null, $: [breadcrumb({ separator: "›" })] }
*/
function breadcrumb(
props: { color?: ValueOrState<ThemeColor>; separator?: string } = {},
): PartialElement {
const { separator = "/" } = props;
const color = toState(props.color ?? "neutral", "color");
return {
_onInsert: (node) => {
if (node.tagName !== "nav")
console.warn('"breadcrumb" patch must use nav tag');
},
ariaLabel: "breadcrumb",
style: {
display: "flex",
alignItems: "center",
flexWrap: "wrap",
fontSize: (listener) => themeSize(listener, "inherit"),
gap: themeSpacing(1),
color: (listener) => themeColor(listener, "shift-9", color.get(listener)),
backgroundColor: (listener) =>
themeColor(listener, "inherit", color.get(listener)),
"& > *": {
display: "inline-flex",
alignItems: "center",
color: (listener) =>
themeColor(listener, "shift-8", color.get(listener)),
},
"& > *:not(:last-child)::after": {
content: `"${separator}"`,
color: (listener) =>
themeColor(listener, "shift-4", color.get(listener)),
paddingInlineStart: themeSpacing(1),
},
"& > [aria-current=page]": {
color: (listener) =>
themeColor(listener, "shift-10", color.get(listener)),
pointerEvents: "none",
},
},
};
}
export { breadcrumb };
</div>
</div>