Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
81048cb
Merge branch 'develop' into spark-55/shine-update-button-base-styles
ttaylor-stack Oct 15, 2025
643ba84
update default and xs
ttaylor-stack Oct 15, 2025
775b57e
Update button.less
ttaylor-stack Oct 17, 2025
1c40dc1
Update based on changes
ttaylor-stack Oct 28, 2025
cf1c920
Merge branch 'spark-55/shine-update-button-base-styles' of https://gi…
ttaylor-stack Oct 28, 2025
7f2cde6
fix duplicate
ttaylor-stack Oct 28, 2025
f2bafc7
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Oct 28, 2025
03be402
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Nov 7, 2025
7836b23
Update button.less
ttaylor-stack Nov 10, 2025
4aa9ee4
update docs
ttaylor-stack Nov 10, 2025
908c113
update button svelte files
ttaylor-stack Nov 10, 2025
553be5f
add changeset
ttaylor-stack Nov 10, 2025
5bacf2a
update dependent svelte files
ttaylor-stack Nov 10, 2025
3864d59
update to theme secondary
ttaylor-stack Nov 10, 2025
ecda33e
Update accessibility tests
ttaylor-stack Nov 11, 2025
0cff80e
remove contextual styles
ttaylor-stack Nov 11, 2025
c43816f
reintroduce contextual styles
ttaylor-stack Nov 11, 2025
dfd0139
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Nov 14, 2025
16d5cde
Update based on figma update and pr comments
ttaylor-stack Nov 14, 2025
965c54c
Update badge background color for danger clear variant
ttaylor-stack Nov 14, 2025
9db5f52
add breaking changes
ttaylor-stack Nov 14, 2025
69ec77a
Update docs
ttaylor-stack Nov 14, 2025
a9b255e
correct gradients
ttaylor-stack Nov 14, 2025
850fdf3
use color instead of opacity
ttaylor-stack Nov 14, 2025
e0719f3
Update based on comments
ttaylor-stack Nov 17, 2025
6cce94a
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Nov 17, 2025
4fe49e2
Button styles refactor (#2052)
dancormier Nov 18, 2025
bcb6f21
update svelte component
ttaylor-stack Nov 19, 2025
bb0d4db
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Nov 19, 2025
b7c8122
Update migration guide
ttaylor-stack Nov 19, 2025
af6aacb
fix lint issue
ttaylor-stack Nov 21, 2025
3ecdc69
Merge branch 'beta' into spark-55/shine-update-button-base-styles
ttaylor-stack Nov 21, 2025
991e62e
Fix button prop in Menu story
dancormier Nov 21, 2025
4a428f2
update visual tests
ttaylor-stack Nov 21, 2025
2ab5354
updsate visual tests
ttaylor-stack Nov 21, 2025
57b422d
update visual regression tests
ttaylor-stack Nov 21, 2025
f8d8bbc
Merge branch 'beta' into spark-55/shine-update-button-base-styles
dancormier Nov 21, 2025
290432f
Update visual regression images
dancormier Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/beige-bats-like.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@stackoverflow/stacks": minor
"@stackoverflow/stacks-svelte": minor
---

Update button to new Shine styles
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ describe("button", () => {
/s-btn-(light|dark).*?badge/,
// matches tests with a badge in highcontrast-light modes, excluding filled, danger, github, facebook, sm, or xs
/s-btn-highcontrast-light-(?!.*(filled|danger|github|facebook|sm|xs)).*?badge/,
// matches tests with a badge in highcontrast-light modes, are muted or featured and/or outlined, and are sm or xs
/s-btn-highcontrast-light-(?:muted-|featured-)?(?:outlined-)?(?:sm|xs).*?badge/,
// matches tests with a badge in highcontrast-light modes, are tonal or featured, and are sm or xs
/s-btn-highcontrast-light-(?:tonal-|featured-)?(?:sm|xs).*?badge/,
],
});
});
180 changes: 88 additions & 92 deletions packages/stacks-classic/lib/components/button/button.less
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,39 @@
--_bu-baw: var(--su-static1);
--_bu-bc: transparent;
// --_bu-bg: inherit; // [1]
--_bu-br: var(--br-md);
--_bu-fc: var(--theme-button-color, var(--theme-secondary-400));
--_bu-br: var(--br-pill); // TODO: confirm this when we have the correct atomic values - SPARK-91
--_bu-fc: var(--theme-button-color, var(--theme-secondary-600));
--_bu-fs: var(--fs-body1);
--_bu-p: 0.8em;
--_bu-p: var(--su16);
--_bu-py: 11.7px; // Adjust to reach 40px height
--_bu-fw: 600; // Semibold font weight
--_bu-icon-gap: 8px; // Default spacing between icons and text

// Active
--_bu-bc-active: var(--_bu-bc);
--_bu-bg-active: var(--theme-button-active-background-color, var(--theme-secondary-300));
--_bu-fc-active: var(--theme-button-hover-color, var(--theme-secondary-500)); // Note: hover color used on purpose
--_bu-bg-active: var(--theme-button-active-background-color, var(--theme-secondary-050));
--_bu-fc-active: var(--theme-button-hover-color, var(--theme-secondary-600)); // Note: hover color used on purpose

// Hover
--_bu-bc-hover: var(--_bu-bc);
--_bu-bg-hover: var(--theme-button-hover-background-color, var(--theme-secondary-200));
--_bu-fc-hover: var(--theme-button-hover-color, var(--theme-secondary-500));
--_bu-bg-hover: var(--theme-button-hover-background-color, var(--theme-secondary-100));
--_bu-fc-hover: var(--theme-button-hover-color, var(--theme-secondary-600));

// Focus
--_bu-bg-focus: var(--black-150);
--_bu-fc-focus: var(--black-600);

// BASE SELECTED MODIFIER
--_bu-bg-selected: var(--theme-button-selected-background-color, var(--theme-secondary-300));
--_bu-bg-selected: linear-gradient(to bottom, var(--black-100) 0%, var(--black-100) 50%, color-mix(in srgb, var(--black-100) 80%, white 20%) 50%, color-mix(in srgb, var(--black-100) 80%, white 20%) 100%);
--_bu-fc-selected: var(--theme-button-selected-color, var(--theme-secondary-600));

// FILLED VARIANT
--_bu-filled-bc: transparent;
--_bu-filled-bg: var(--theme-button-primary-background-color, var(--theme-secondary-400));
--_bu-filled-fc: var(--theme-button-primary-color, var(--white));
--_bu-filled-bg: var(--theme-button-primary-background-color, var(--theme-secondary-600));
--_bu-filled-fc: var(--theme-button-primary-color, var(--black-050));
// Filled + Selected
--_bu-filled-bc-selected: transparent;
--_bu-filled-bg-selected: var(--theme-button-primary-selected-background-color, var(--theme-secondary-500));
--_bu-filled-bg-selected: linear-gradient(to bottom, var(--theme-secondary-600) 0%, var(--theme-secondary-600) 50%, color-mix(in srgb, var(--theme-secondary-600) 80%, white 20%) 50%, color-mix(in srgb, var(--theme-secondary-600) 80%, white 20%) 100%);
--_bu-filled-fc-selected: var(--theme-button-primary-selected-color, var(--white));
// Filled + Active
--_bu-filled-bc-active: var(--_bu-filled-bc);
Expand All @@ -38,15 +45,9 @@
--_bu-filled-bc-hover: var(--_bu-filled-bc);
--_bu-filled-bg-hover: var(--theme-button-primary-hover-background-color, var(--theme-secondary-500));
--_bu-filled-fc-hover: var(--theme-button-primary-hover-color, var(--white));

// OUTLINED VARIANT
--_bu-outlined-bc: var(--theme-button-outlined-border-color, var(--theme-secondary-400));
--_bu-outlined-bg: var(--theme-button-outlined-background-color);
--_bg-outlined-fc: var(--theme-button-outlined-color, var(--theme-secondary-400));
// Outlined + Selected
--_bu-outlined-bc-selected: var(--theme-button-outlined-selected-border-color, var(--theme-secondary-400));
--_bu-outlined-bg-selected: var(--theme-button-selected-background-color, var(--theme-secondary-300));
--_bu-outlined-fc-selected: var(--theme-button-selected-color, var(--theme-secondary-600));
// Filled + Focus
--_bu-filled-bg-focus: var(--black-600);
--_bu-filled-fc-focus: var(--black-50);

// CHILD COMPONENT CUSTOM PROPERTIES
--_bu-badge-o: 0.5;
Expand All @@ -58,9 +59,7 @@
// CONTEXTUAL STYLES
.highcontrast-mode({
--_bu-bc: currentColor;
--_bu-outlined-bc: var(--_bu-bc);
--_bu-fc-selected: var(--white);
--_bu-outlined-fc-selected: var(--white);
--_bu-badge-o: 0.8;
--_bu-number-fc-selected: var(--theme-button-primary-number-color, var(--theme-secondary-600));
});
Expand Down Expand Up @@ -96,6 +95,9 @@
&.is-selected,
&--radio:checked + & {
background-color: var(--_bu-bg-selected);
background-image: var(--_bu-bg-selected);
background-origin: border-box;
background-clip: border-box;
border-color: var(--_bu-bc-selected, transparent);
color: var(--_bu-fc-selected);

Expand All @@ -106,22 +108,11 @@
&.s-btn__filled { // this needs to live here to adapt to radio button-group
border-color: var(--_bu-filled-bc-selected);
background-color: var(--_bu-filled-bg-selected);
background-image: var(--_bu-filled-bg-selected);
background-origin: border-box;
background-clip: border-box;
color: var(--_bu-filled-fc-selected);
}
&.s-btn__outlined { // this needs to live here to adapt to radio button-group
border-color: var(--_bu-outlined-bc-selected);
background-color: var(--_bu-outlined-bg-selected);
color: var(--_bu-outlined-fc-selected);

&.s-btn__muted {
.highcontrast-mode({
--_bu-outlined-bc-selected: var(--_bu-filled-bc-selected);
--_bu-outlined-bg-selected: var(--_bu-filled-bg-selected);
--_bu-outlined-fc-selected: var(--_bu-filled-fc-selected);
--_bu-number-fc-selected: var(--_bu-filled-bg-selected);
});
}
}
}

// MODIFIERS
Expand All @@ -135,11 +126,6 @@
color: var(--_bu-filled-fc);
}

&&__outlined {
border-color: var(--_bu-outlined-bc);
background-color: var(--_bu-outlined-bg, inherit);
}

// Resets
&&__link,
&&__unset {
Expand Down Expand Up @@ -214,58 +200,81 @@
margin-top: -0.3em; // [4]
margin-bottom: -0.3em; // [4]
transition: opacity 200ms var(--te-smooth); // Animate the transition to .is-loading

&:not(:last-child) {
margin-right: var(--_bu-icon-gap);
}

&:not(:first-child) {
margin-left: var(--_bu-icon-gap);
}
}
}

// Size
// TODO: port the below added styles to the size-styles mixin SPARK-91 and SPARK-102
&&__xs {
.size-styles(xs; bu; @styles: fs);
--_bu-dropdown-bw: calc(var(--su-static4) - var(--su-static1));
--_bu-p: 0.6em;
--_bu-p: var(--su12);
--_bu-py: 6.285px; // Adjust to reach 28px height
--_bu-fs: var(--su12); // Override size-styles for custom font size
--_bu-icon-gap: var(--su4); // 4px spacing as per Figma specs
}

&&__sm {
.size-styles(sm; bu; @styles: fs);
--_bu-p: var(--su12);
--_bu-py: 7.7px; // Adjust to reach 32px height
--_bu-fs: calc(var(--su12) + var(--su1)); // Override size-styles for custom font size
--_bu-icon-gap: var(--su6); // 6px spacing as per Figma specs
}

&&__md {
&&__lg {
.size-styles(md; bu; @styles: br, fs);
--_bu-p: 0.7em;
--_bu-br: var(--br-pill); // TODO: figure out why this isn't automatically applied
--_bu-p: var(--su24);
--_bu-py: 13.98px; // Adjust to reach 48px height
--_bu-fs: var(--su16); // Override size-styles for custom font size
}

// VARIANTS
&&__danger,
&&__featured,
&&__muted {
&&__tonal {
.highcontrast-mode({
--_bu-filled-bc: transparent;
});
}

&&__danger {
--_bu-bg-active: var(--red-300);
--_bu-bg-hover: var(--red-200);
--_bu-bg-selected: var(--red-300);
--_bu-fc: var(--red-500);
--focus-theme: #C91D3F;
--_bu-bg-active: var(--black-050);
--_bu-bg-hover: var(--red-100);
--_bu-bg-selected: linear-gradient(to bottom, var(--red-100) 0%, var(--red-100) 50%, color-mix(in srgb, var(--red-100) 80%, white 20%) 50%, color-mix(in srgb, var(--red-100) 80%, white 20%) 100%);
--_bu-bg-focus: var(--black-050);
--_bu-fc: var(--red-400);
--_bu-fc-active: var(--_bu-fc);
--_bu-fc-hover: var(--red-500);
--_bu-fc-selected: var(--red-600);
--_bu-fc-selected: var(--red-500);
--_bu-fc-focus: var(--red-400);
--_bu-filled-bc: transparent;
--_bu-filled-bc-selected: var(--_bu-filled-bc);
--_bu-filled-bg: var(--red-400);
--_bu-filled-bg-active: var(--red-500);
--_bu-filled-bg-hover: var(--red-500);
--_bu-filled-bg-selected: var(--red-600);
--_bu-filled-bg-selected: linear-gradient(to bottom, var(--red-500) 0%, var(--red-500) 50%, color-mix(in srgb, var(--red-500) 80%, white 20%) 50%, color-mix(in srgb, var(--red-500) 80%, white 20%) 100%);
--_bu-filled-fc: var(--white);
--_bu-filled-bg-focus: var(--red-400);
--_bu-filled-fc-active: var(--_bu-filled-fc);
--_bu-filled-fc-hover: var(--_bu-filled-fc);
--_bu-filled-fc-selected: var(--_bu-filled-fc);
--_bu-outlined-bc: var(--red-400);
--_bu-outlined-bc-selected: var(--red-500);
--_bu-outlined-bg-selected: var(--_bu-bg-selected);
--_bu-outlined-fc-selected: var(--_bu-fc-selected);
--_bu-number-fc: var(--white);
--_bu-number-fc-filled: var(--black);

&&__filled {
--focus-theme: var(--red-400);
}
}

&&__featured {
Expand All @@ -281,49 +290,31 @@
--_bu-filled-bg: var(--purple-400);
--_bu-filled-bg-active: var(--purple-500);
--_bu-filled-bg-hover: var(--purple-500);
--_bu-filled-bg-selected: var(--purple-600);
--_bu-filled-bg-selected: linear-gradient(to bottom, var(--purple-500) 0%, var(--purple-500) 50%, color-mix(in srgb, var(--purple-500) 80%, white 20%) 50%, color-mix(in srgb, var(--purple-500) 80%, white 20%) 100%);
--_bu-filled-fc: var(--white);
--_bu-filled-fc-active: var(--_bu-filled-fc);
--_bu-filled-fc-hover: var(--_bu-filled-fc);
--_bu-filled-fc-selected: var(--_bu-filled-fc);
--_bu-outlined-bc: var(--purple-400);
--_bu-outlined-bc-selected: var(--purple-500);
--_bu-outlined-bg-selected: var(--_bu-bg-selected);
--_bu-outlined-fc-selected: var(--_bu-fc-selected);
--_bu-filled-bg-focus: var(--purple-400);
--_bu-number-fc: var(--white);
--_bu-number-fc-filled: var(--black);
--focus-theme: var(--purple-400);
}

&&__muted {
--_bu-bc-hover: var(--black-300);
--_bu-bg-active: var(--black-150);
--_bu-bg-hover: var(--black-100);
--_bu-bg-selected: var(--black-200);
--_bu-fc: var(--black-500);
&&__tonal {
--_bu-bg: var(--theme-secondary-150);
--_bu-bc-hover: transparent;
--_bu-bg-active: var(--theme-secondary-150);
--_bu-bg-hover: var(--theme-secondary-200);
--_bu-bg-selected: linear-gradient(to bottom, var(--theme-secondary-200) 0%, var(--theme-secondary-200) 50%, color-mix(in srgb, var(--theme-secondary-200) 80%, white 20%) 50%, color-mix(in srgb, var(--theme-secondary-200) 80%, white 20%) 100%);
--_bu-fc: var(--theme-secondary-600);
--_bu-fc-active: var(--_bu-fc);
--_bu-fc-hover: var(--black-500);
--_bu-fc-selected: var(--black-500);
// The filled modifier on the muted button is deprecated and is to be
// removed in Stacks Classic v2
--_bu-filled-bc: transparent;
--_bu-filled-bc-selected: var(--_bu-filled-bc);
--_bu-filled-bg: var(--black-225);
--_bu-filled-bg-active: var(--black-300);
--_bu-filled-bg-hover: var(--black-250);
--_bu-filled-bg-selected: var(--black-350);
--_bu-filled-fc: var(--black-500);
--_bu-filled-fc-active: var(--_bu-filled-fc);
--_bu-filled-fc-hover: var(--_bu-filled-fc);
--_bu-filled-fc-selected: var(--black-600);
--_bu-outlined-bc: var(--black-300);
--_bu-outlined-bc-selected: var(--black-300);
--_bu-outlined-bg-selected: var(--_bu-bg-selected);
--_bu-outlined-fc-selected: var(--_bu-fc-selected);
--_bu-fc-hover: var(--theme-secondary-600);
--_bu-fc-selected: var(--theme-secondary-600);
--_bu-number-fc-filled: var(--white);
--_bu-number-fc-selected: var(--white);
--_bu-bg-focus: var(--black-400);
--_bu-fc-focus: var(--white);
--_bu-number-fc-focus: var(--black-500);
--_bu-bg-focus: var(--theme-secondary-150);
--_bu-number-fc-focus: var(--theme-secondary-600);

.highcontrast-mode({
--_bu-bc-hover: currentColor;
Expand Down Expand Up @@ -353,7 +344,7 @@
}

&&__facebook {
@_fb-brand: #385499;
@_fb-brand: #1877F2;
--_bu-bc: transparent;
--_bu-bg: @_fb-brand;
--_bu-bg-active: darken(@_fb-brand, 10%);
Expand All @@ -366,7 +357,7 @@

&&__google {
--_bu-bc: var(--bc-medium);
--_bu-bg: var(--white);
--_bu-bg: var(--black-150);
--_bu-bg-active: var(--black-150);
--_bu-bg-hover: var(--black-100);
--_bu-fc: var(--fc-medium);
Expand Down Expand Up @@ -425,6 +416,11 @@
color: var(--_bu-number-fc-focus, var(--_bu-number-fc-filled));
}

&.s-btn__filled {
background-color: var(--_bu-filled-bg-focus, var(--_bu-filled-bg));
color: var(--_bu-filled-fc-focus, var(--_bu-filled-fc));
}

background-color: var(--_bu-bg-focus, var(--_bu-filled-bg));
color: var(--_bu-fc-focus, var(--_bu-filled-fc));
}
Expand All @@ -436,12 +432,12 @@
color: var(--_bu-filled-fc-hover);
}

&:not(.s-btn__outlined):not(.s-btn__filled) {
&:not(.s-btn__toned):not(.s-btn__filled) {
border-color: var(--_bu-bc-hover);
}

&:visited:not(:active):not(:focus) {
&:not(.s-btn__outlined) {
&:not(.s-btn__toned) {
&.s-btn__filled {
background-color: var(--_bu-filled-bg-hover);
border-color: var(--_bu-filled-bc-hover);
Expand Down Expand Up @@ -482,7 +478,7 @@
cursor: pointer;
display: inline-block;
font-family: inherit;
font-weight: normal;
font-weight: var(--_bu-fw, 600);
line-height: var(--lh-sm);
position: relative;
outline: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ const getChild = (child?: string): string => {
// TODO test disabled states, interaction pseudo-classes
const testArgs: TestVariationArgs = {
baseClass: "s-btn",
variants: ["danger", "featured", "muted"],
variants: ["danger", "featured", "tonal"],
modifiers: {
primary: ["filled", "outlined"],
primary: ["filled"],
secondary: [...["xs", "sm", "md"], ...["dropdown", "icon"]],
global: ["is-loading"],
standalone: [...["link", "unset"], ...["facebook", "github", "google"]],
Expand Down
Loading
Loading