From 562ed24ebdbb7655581d0b330a53c24abb3406ff Mon Sep 17 00:00:00 2001 From: web-padawan Date: Tue, 9 Jun 2026 14:30:05 +0300 Subject: [PATCH 1/2] feat: add slash separator theme variant to breadcrumbs Add a `theme="slash"` variant on `` that swaps the chevron separator for a slash. The variant rebinds `--vaadin-breadcrumbs-separator` to a new `--_vaadin-icon-slash` icon token in the shared icon set, so themes and applications inherit the variant for free. --- .../breadcrumbs/spec/web-component-spec.md | 8 ++++++ .../styles/vaadin-breadcrumbs-base-styles.js | 4 +++ .../test/visual/base/breadcrumbs.test.js | 24 ++++++++++++++++++ .../breadcrumbs/baseline/theme-slash.png | Bin 0 -> 2473 bytes .../component-base/src/styles/style-props.js | 1 + 5 files changed, 37 insertions(+) create mode 100644 packages/breadcrumbs/test/visual/base/screenshots/breadcrumbs/baseline/theme-slash.png diff --git a/packages/breadcrumbs/spec/web-component-spec.md b/packages/breadcrumbs/spec/web-component-spec.md index 29c6f3a631a..9c2164cf9d6 100644 --- a/packages/breadcrumbs/spec/web-component-spec.md +++ b/packages/breadcrumbs/spec/web-component-spec.md @@ -83,6 +83,10 @@ The overflow overlay's outer panel and inner wrapper are re-exported on the brea |---|---| | `has-overflow` | Set when one or more items are collapsed into the overflow overlay. | +| Theme | Description | +|---|---| +| `slash` | Renders a slash (`/`) instead of the default chevron between items. Set via `theme="slash"` on ``. | + | CSS Custom Property | Default | Description | |---|---|---| | `--vaadin-breadcrumbs-overflow-icon` | `var(--_vaadin-icon-ellipsis)` | The mask-image icon used inside the overflow button. | @@ -322,3 +326,7 @@ When an item's text wraps onto multiple lines (very narrow viewport, long curren **Q: Why does each item carry a padding-based click target paired with a negative `margin-inline`?** The inline padding gives the link a hit area noticeably larger than the visible text, matching the WCAG 2.5.8 minimum target size and aligning with how trail items render an offset focus outline. The negative `margin-inline` exactly cancels the inline padding for layout, so the visual width and the trail's gaps look the same as a no-padding rendering — the trail still reads as text first, while clicks within the larger hit area still register. Overlay items skip the negative-margin compensator because they need the visual padding (their hover/focus background fills the row). + +**Q: Why does base styles ship a `theme="slash"` separator variant rather than leaving it to each theme?** + +The slash is the second common breadcrumb separator convention after the chevron, and the mask-image recipe makes the variant trivial — `theme="slash"` rebinds `--vaadin-breadcrumbs-separator` to the bundled `--_vaadin-icon-slash` token. Shipping it in base means applications written without a Vaadin theme still get the variant for free, and Lumo / Aura themes do not have to re-implement the same selector. diff --git a/packages/breadcrumbs/src/styles/vaadin-breadcrumbs-base-styles.js b/packages/breadcrumbs/src/styles/vaadin-breadcrumbs-base-styles.js index 92a9fb9c0aa..20a4de68c9b 100644 --- a/packages/breadcrumbs/src/styles/vaadin-breadcrumbs-base-styles.js +++ b/packages/breadcrumbs/src/styles/vaadin-breadcrumbs-base-styles.js @@ -85,6 +85,10 @@ export const breadcrumbsStyles = css` transform: scaleX(-1); } + :host([theme~='slash']) { + --vaadin-breadcrumbs-separator: var(--_vaadin-icon-slash); + } + @media (forced-colors: active) { [part='overflow-button']::before, [part='overflow']::after { diff --git a/packages/breadcrumbs/test/visual/base/breadcrumbs.test.js b/packages/breadcrumbs/test/visual/base/breadcrumbs.test.js index 27a9341750a..720fc4d03f9 100644 --- a/packages/breadcrumbs/test/visual/base/breadcrumbs.test.js +++ b/packages/breadcrumbs/test/visual/base/breadcrumbs.test.js @@ -119,4 +119,28 @@ describe('breadcrumbs', () => { await visualDiff(div, 'overflow-opened'); }); }); + + describe('theme', () => { + let breadcrumbs; + + beforeEach(async () => { + fixtureSync( + ` + + Home + Docs + Current + + `, + div, + ); + breadcrumbs = div.querySelector('vaadin-breadcrumbs'); + await nextRender(); + }); + + it('slash', async () => { + breadcrumbs.setAttribute('theme', 'slash'); + await visualDiff(div, 'theme-slash'); + }); + }); }); diff --git a/packages/breadcrumbs/test/visual/base/screenshots/breadcrumbs/baseline/theme-slash.png b/packages/breadcrumbs/test/visual/base/screenshots/breadcrumbs/baseline/theme-slash.png new file mode 100644 index 0000000000000000000000000000000000000000..73a9a161e669f7393c3850b1165eb908376204b2 GIT binary patch literal 2473 zcmb_e`#Tft8=n+XS~(<#C~|6)N)FB8i%?uj_uU=X2lB^SQ52DimTNA}lQo002a;U%P4t z0PN>(0T+e#aaZdHhMoYxLHPBn#tt!P=9tZG87klV6&1@&ziz^@bg_ZZWJt%Z6|h@CRrX95If8#wGZ^olxC6?r&;AumG)A|^cE=odGCW^ zgSL6&(gPX;Wv2bB{l(cz*8b{`NfnWbRO*|-dq%URv4v82L_A^Bzu)&nGLMr7ke^2? zG2|#O0?3^H1KK8kAo$@Q_$I{1!^UI0On`^tpJLvc3-O}FjQ{oEHXY#Mpi`n$R@1vO zEHiH7o8{1A72r1`Z9G?PYUh1d5d7ryV8&9R;(^T`IvxrY5gRB5l-&}*U` zmz|xRPoF-O+*`e#^@~80#pJo%)82fXx!Icr)|(U2shl7(Fm7}cqZm<*hi{juF`_S%rq z)+B$p^58AvE(7GHLa7Oy@vQ9JR+lpffCNKw$%|)FUlL&#{Unk}B|SSquOSHIzo^kI zXJn03*Ktp)8i|bV6%^Lp0P=X<&-EXB6GjdnOBoV(Vh{ z?Ofep=jXdVgRvI;p$HGwU=r=;`w~cMPp?J9nAme%Jotx<9D(zTR*6-V;|eeFZa?{} zb9)nRD@1FJ4HYA!gf5Kkj%y1JnnkM0wKhN0VHT%p+vA?)+=(S+Vy1*1p^*)}C3kH8 z#(XmNSJgdrka9J~qmJfu`E*`k5&6E)KtQp&NqwVxzU9e~9_mj!_K@KYbEM7%QfZIQ z>kS$y4ZJrYp=TS&?-T@&z@^tUG&+M zc+2|Xju-J*{}|oLwKg-K$ah%Bu-V|t0$edH#T^2KTIeUt8ENw&2neDhJwvZ^%=F_i z)}fI1(l>yFn8*2XES1N}6_E~@Tz9a;0OPXh3OEV=xtv>rs`zn9$v#Hu^YTr2i-b8Q zSZFCx3YM96a5GZv>8pn2kWvMAzF1j#)aCf_fZs}`Uz%t$Ayon6`} zNQf9?J}km7Q`&yGhYbh$wSGgk!SuRNikdweaPFI6Z-((rT6jlwyuKe3s45k~ieJcg zN6xJjm=5>;U=ExpPXT$}Z8l-QRo=fatz>wF^A6mskhdDAJjS;EdtDQyCbg)>k1ks+ z{*TYQ7F#tZ)^p0JDOU86zt7ny#C&}Gp<5F`0ASha%9wht6tNBo%DE&fPYgYhz+4D^cEuo+U)OAU?EdHHw(fO}N)!SosjH)_9Ug0V{-33@ zC$Z;`F3)0MFQyH+0*$`20hmlzay1ztbv3M`(K*F=kDNuBArb_g$kQ`RK9azlgqPpw zbh@Pby>P~eMz~XQj?uLD~tMYn$Zb67wWz5^F&ZxaO*;bTgvac)yB~qm02}o zhFv30!6eF**XTMr$2gn3xOR{3|uwu zjx+Z!hcm+ay3SveTM?J9tKVcn<+0m3BP5xr13cBtk;C>u&dKds>a5NsEsgI->woxQ zl3(<3sykD`B=u!5G5f{0HNnjXD~hPV+ZyzoVJBpZ+ipefMDVk`)=sLrn)&64f&A}| zIGh?{qh_I#Ho{JtWA?S_{wCXyOV-t?ShApiwjPUxf1ks>A9HR zxavEsM%moOzPQoP@ij#GwTyAn?mF^KbGEZ{VTrYsjSVEzx?xGGXGz{ r@ZUHT4tI=jIKp3kj&KPG@SGMufXUd!p}!g;c;v2|L9W)Dcs%$Qk)DjG literal 0 HcmV?d00001 diff --git a/packages/component-base/src/styles/style-props.js b/packages/component-base/src/styles/style-props.js index ba25dfdf8d0..93a6664e8d8 100644 --- a/packages/component-base/src/styles/style-props.js +++ b/packages/component-base/src/styles/style-props.js @@ -104,6 +104,7 @@ addGlobalStyles( --_vaadin-icon-redo: url('data:image/svg+xml;utf8,'); --_vaadin-icon-refresh: url('data:image/svg+xml;utf8,'); --_vaadin-icon-resize: url('data:image/svg+xml;utf8,'); + --_vaadin-icon-slash: url('data:image/svg+xml;utf8,'); --_vaadin-icon-sort: url('data:image/svg+xml;utf8,'); --_vaadin-icon-undo: url('data:image/svg+xml;utf8,'); --_vaadin-icon-upload: url('data:image/svg+xml;utf8,'); From e5c102894cd51435432ae97aeac34778f4f46202 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Wed, 10 Jun 2026 10:40:59 +0300 Subject: [PATCH 2/2] docs: mention slash icon in the spec --- packages/breadcrumbs/spec/web-component-spec.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/breadcrumbs/spec/web-component-spec.md b/packages/breadcrumbs/spec/web-component-spec.md index 9c2164cf9d6..79e8f0c3822 100644 --- a/packages/breadcrumbs/spec/web-component-spec.md +++ b/packages/breadcrumbs/spec/web-component-spec.md @@ -201,14 +201,16 @@ Internal behavior: ### `packages/component-base/src/styles/style-props.js` — Modification needed -Add a `--_vaadin-icon-chevron-right` icon definition alongside the existing `--_vaadin-icon-chevron-down`: +Add two icon definitions to the shared icon set: + +- `--_vaadin-icon-chevron-right` — the default separator icon. The breadcrumb separator defaults to a right-pointing chevron, which did not exist in the shared icon set. +- `--_vaadin-icon-slash` — the icon bound to `--vaadin-breadcrumbs-separator` by the `theme="slash"` variant (see "Theme" table on the container). ```css --_vaadin-icon-chevron-right: url('data:image/svg+xml;utf8,'); +--_vaadin-icon-slash: url('data:image/svg+xml;utf8,'); ``` -The breadcrumb separator defaults to a right-pointing chevron. This icon does not exist in the shared icon set. - ### `packages/component-base/src/i18n-mixin.js` — Used as-is Provides the `i18n` property with a `moreItems` key for localizing the overflow button's `aria-label`.