diff --git a/examples/button-state-verification.html b/examples/button-state-verification.html
new file mode 100644
index 0000000..6e0c42c
--- /dev/null
+++ b/examples/button-state-verification.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+ Button State Verification
+
+
+
+
+ Button State Verification
+
+
+ Aria-Busy (Loading) State
+
+
+
+
+
+
+
+
+
+ Aria-Disabled State
+
+
+
+
+
+
+
+
+
+
+ Forced States (Recipe Output Verification)
+
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 99b3e56..be9fa98 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4363,6 +4363,7 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+ "dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
diff --git a/src/recipes/button.ts b/src/recipes/button.ts
index 9b85939..86a9f87 100644
--- a/src/recipes/button.ts
+++ b/src/recipes/button.ts
@@ -85,9 +85,9 @@ export function getButtonClasses(opts: ButtonRecipeOptions = {}): string {
fullWidth && "sp-btn--full",
loading && "sp-btn--loading",
disabled && "sp-btn--disabled",
- hovered && "sp-btn--hover",
- focused && "sp-btn--focus",
- active && "sp-btn--active",
+ hovered && "sp-btn--hover is-hover",
+ focused && "sp-btn--focus is-focus",
+ active && "sp-btn--active is-active",
iconOnly && "sp-btn--icon",
pill && "sp-btn--pill",
);
diff --git a/src/styles/components.css b/src/styles/components.css
index e84c02b..d869d2a 100644
--- a/src/styles/components.css
+++ b/src/styles/components.css
@@ -271,7 +271,8 @@
pointer-events: none;
}
- .sp-btn--loading {
+ .sp-btn--loading,
+ .sp-btn[aria-busy="true"] {
pointer-events: none;
opacity: var(--sp-opacity-active);
}
@@ -338,6 +339,7 @@
}
.sp-btn--primary.sp-btn--disabled,
+ .sp-btn--primary[aria-disabled="true"],
.sp-btn--primary:disabled {
background-color: var(--sp-component-button-primary-bg-disabled);
color: var(--sp-component-button-primary-text-disabled);
@@ -364,6 +366,7 @@
}
.sp-btn--secondary.sp-btn--disabled,
+ .sp-btn--secondary[aria-disabled="true"],
.sp-btn--secondary:disabled {
background-color: var(--sp-component-button-secondary-bg-disabled);
color: var(--sp-component-button-secondary-text-disabled);
@@ -389,6 +392,7 @@
}
.sp-btn--ghost.sp-btn--disabled,
+ .sp-btn--ghost[aria-disabled="true"],
.sp-btn--ghost:disabled {
color: var(--sp-component-button-ghost-text-disabled);
background-color: var(--sp-component-button-ghost-bg-disabled);
@@ -413,6 +417,7 @@
}
.sp-btn--danger.sp-btn--disabled,
+ .sp-btn--danger[aria-disabled="true"],
.sp-btn--danger:disabled {
background-color: var(--sp-component-button-danger-bg-disabled);
color: var(--sp-component-button-danger-text-disabled);
@@ -437,6 +442,7 @@
}
.sp-btn--success.sp-btn--disabled,
+ .sp-btn--success[aria-disabled="true"],
.sp-btn--success:disabled {
background-color: var(--sp-component-button-success-bg-disabled);
color: var(--sp-component-button-success-text-disabled);
@@ -462,6 +468,7 @@
}
.sp-btn--cta.sp-btn--disabled,
+ .sp-btn--cta[aria-disabled="true"],
.sp-btn--cta:disabled {
background-color: var(--sp-component-button-cta-bg-disabled);
color: var(--sp-component-button-cta-text-disabled);
@@ -487,6 +494,7 @@
}
.sp-btn--accent.sp-btn--disabled,
+ .sp-btn--accent[aria-disabled="true"],
.sp-btn--accent:disabled {
background-color: var(--sp-component-button-accent-bg-disabled);
color: var(--sp-component-button-accent-text-disabled);
diff --git a/tests/button-recipe.test.ts b/tests/button-recipe.test.ts
index ed1aae1..1517371 100644
--- a/tests/button-recipe.test.ts
+++ b/tests/button-recipe.test.ts
@@ -61,9 +61,9 @@ describe('getButtonClasses', () => {
expect(result).toContain('sp-btn--full');
expect(result).toContain('sp-btn--loading');
expect(result).toContain('sp-btn--disabled');
- expect(result).toContain('sp-btn--hover');
- expect(result).toContain('sp-btn--focus');
- expect(result).toContain('sp-btn--active');
+ expect(result).toContain('sp-btn--hover is-hover');
+ expect(result).toContain('sp-btn--focus is-focus');
+ expect(result).toContain('sp-btn--active is-active');
expect(result).toContain('sp-btn--icon');
expect(result).toContain('sp-btn--pill');
});
diff --git a/tests/css-contract.test.ts b/tests/css-contract.test.ts
index 88d7630..28ff502 100644
--- a/tests/css-contract.test.ts
+++ b/tests/css-contract.test.ts
@@ -207,19 +207,35 @@ const interactionStateContracts = [
'.sp-btn.sp-btn--disabled',
'.sp-btn[aria-disabled="true"]',
'.sp-btn:disabled',
+ '.sp-btn--loading',
+ '.sp-btn[aria-busy="true"]',
'.sp-btn--primary:hover',
+ '.sp-btn--primary.sp-btn--disabled',
+ '.sp-btn--primary[aria-disabled="true"]',
'.sp-btn--primary:disabled',
'.sp-btn--secondary:hover',
+ '.sp-btn--secondary.sp-btn--disabled',
+ '.sp-btn--secondary[aria-disabled="true"]',
'.sp-btn--secondary:disabled',
'.sp-btn--ghost:hover',
+ '.sp-btn--ghost.sp-btn--disabled',
+ '.sp-btn--ghost[aria-disabled="true"]',
'.sp-btn--ghost:disabled',
'.sp-btn--danger:hover',
+ '.sp-btn--danger.sp-btn--disabled',
+ '.sp-btn--danger[aria-disabled="true"]',
'.sp-btn--danger:disabled',
'.sp-btn--success:hover',
+ '.sp-btn--success.sp-btn--disabled',
+ '.sp-btn--success[aria-disabled="true"]',
'.sp-btn--success:disabled',
'.sp-btn--cta:hover',
+ '.sp-btn--cta.sp-btn--disabled',
+ '.sp-btn--cta[aria-disabled="true"]',
'.sp-btn--cta:disabled',
'.sp-btn--accent:hover',
+ '.sp-btn--accent.sp-btn--disabled',
+ '.sp-btn--accent[aria-disabled="true"]',
'.sp-btn--accent:disabled',
],
},