diff --git a/apps/prs/angular/src/routes/bugs/3648/bug3648.component.html b/apps/prs/angular/src/routes/bugs/3648/bug3648.component.html
new file mode 100644
index 0000000000..29a3a4a470
--- /dev/null
+++ b/apps/prs/angular/src/routes/bugs/3648/bug3648.component.html
@@ -0,0 +1,60 @@
+
+
3648 - Badge refinements
+
+
+ View on GitHub
+
+
+
+
Strong emphasis badges (edge treatment should be removed)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Strong emphasis, large size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Subtle emphasis badges (reference, no changes needed)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/prs/angular/src/routes/bugs/3648/bug3648.component.ts b/apps/prs/angular/src/routes/bugs/3648/bug3648.component.ts
new file mode 100644
index 0000000000..d072bd3691
--- /dev/null
+++ b/apps/prs/angular/src/routes/bugs/3648/bug3648.component.ts
@@ -0,0 +1,10 @@
+import { Component } from "@angular/core";
+import { GoabBadge } from "@abgov/angular-components";
+
+@Component({
+ standalone: true,
+ selector: "abgov-bug3648",
+ templateUrl: "./bug3648.component.html",
+ imports: [GoabBadge],
+})
+export class Bug3648Component {}
diff --git a/apps/prs/angular/src/routes/bugs/3648/bug3648.route.json b/apps/prs/angular/src/routes/bugs/3648/bug3648.route.json
new file mode 100644
index 0000000000..b5937d264b
--- /dev/null
+++ b/apps/prs/angular/src/routes/bugs/3648/bug3648.route.json
@@ -0,0 +1,6 @@
+{
+ "title": "Badge edge treatment",
+ "path": "bugs/3648",
+ "id": "3648",
+ "type": "bug"
+}
diff --git a/apps/prs/react/src/app/routes/bugs/bug3648.route.ts b/apps/prs/react/src/app/routes/bugs/bug3648.route.ts
new file mode 100644
index 0000000000..3f56e33311
--- /dev/null
+++ b/apps/prs/react/src/app/routes/bugs/bug3648.route.ts
@@ -0,0 +1,9 @@
+import { Bug3648Route } from "../../../routes/bugs/bug3648";
+import type { PrRouteDefinition } from "../../route-manifest";
+export default {
+ type: "bug",
+ id: "3648",
+ path: "bugs/3648",
+ title: "Badge edge treatment",
+ component: Bug3648Route,
+} satisfies PrRouteDefinition;
diff --git a/apps/prs/react/src/routes/bugs/bug3648.tsx b/apps/prs/react/src/routes/bugs/bug3648.tsx
new file mode 100644
index 0000000000..856ecc883f
--- /dev/null
+++ b/apps/prs/react/src/routes/bugs/bug3648.tsx
@@ -0,0 +1,106 @@
+import {
+ GoabBlock,
+ GoabText,
+ GoabDivider,
+ GoabDetails,
+ GoabLink,
+ GoabBadge,
+} from "@abgov/react-components";
+
+export function Bug3648Route() {
+ return (
+
+
+ Bug #3648: Badge refinements
+
+
+
+
+
+ View on GitHub
+
+
+
+
+
+ High emphasis badges have a visible edge treatment that contrasts with the
+ badge background. This is likely an inner shadow or similar, not an actual CSS
+ border. Figma has no such treatment. Remove it from high emphasis badges.
+
+
+
+
+
+
+
Test Cases
+
+
+ High emphasis (strong) badges - inspect for edge treatment
+
+
+ Each of these should have NO visible edge/border/shadow. Inspect to see what CSS
+ creates the visible edge (box-shadow on line 224 of Badge.svelte uses
+ --goa-badge-border token).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Strong emphasis, large size
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Subtle emphasis badges (reference, no changes needed)
+
+ These use their own box-shadow tokens for the edge and should remain unchanged.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Bug3648Route;
diff --git a/libs/react-components/specs/badge.browser.spec.tsx b/libs/react-components/specs/badge.browser.spec.tsx
new file mode 100644
index 0000000000..a6de182bed
--- /dev/null
+++ b/libs/react-components/specs/badge.browser.spec.tsx
@@ -0,0 +1,56 @@
+import { render } from "vitest-browser-react";
+import { GoabBadge } from "../src";
+import { expect, describe, it, vi } from "vitest";
+
+describe("Badge V2 Emphasis", () => {
+ it("should have an explicit box-shadow none rule on strong emphasis", async () => {
+ const result = render(
+ ,
+ );
+
+ const badge = result.getByTestId("badge-strong");
+
+ await vi.waitFor(() => {
+ const el = badge.element();
+ expect(el).toBeTruthy();
+ expect(el.classList.contains("v2")).toBe(true);
+ expect(el.classList.contains("badge-strong")).toBe(true);
+
+ // Verify the shadow DOM stylesheet has an explicit box-shadow: none rule for strong
+ const root = el.getRootNode() as ShadowRoot;
+ const sheet = root.adoptedStyleSheets?.[0] ?? root.querySelector("style")?.sheet;
+ const rules = Array.from(sheet?.cssRules ?? []);
+ const strongRule = rules.find(
+ (r) => r instanceof CSSStyleRule && r.selectorText?.includes("badge-strong"),
+ ) as CSSStyleRule | undefined;
+ expect(strongRule).toBeTruthy();
+ expect(strongRule!.style.boxShadow).toBe("none");
+ });
+ });
+
+ it("should render subtle emphasis with correct classes and shadow rule", async () => {
+ const result = render(
+ ,
+ );
+
+ const badge = result.getByTestId("badge-subtle");
+
+ await vi.waitFor(() => {
+ const el = badge.element();
+ expect(el).toBeTruthy();
+ expect(el.classList.contains("v2")).toBe(true);
+ expect(el.classList.contains("badge-subtle")).toBe(true);
+ expect(el.classList.contains("badge-information")).toBe(true);
+
+ // Verify the shadow DOM stylesheet contains the box-shadow rule for subtle badges
+ const root = el.getRootNode() as ShadowRoot;
+ const sheet = root.adoptedStyleSheets?.[0] ?? root.querySelector("style")?.sheet;
+ const rules = Array.from(sheet?.cssRules ?? []);
+ const subtleRule = rules.find(
+ (r) => r instanceof CSSStyleRule && r.selectorText?.includes("badge-subtle") && r.selectorText?.includes("badge-information"),
+ ) as CSSStyleRule | undefined;
+ expect(subtleRule).toBeTruthy();
+ expect(subtleRule!.style.boxShadow).toContain("--goa-badge-info-subtle-border");
+ });
+ });
+});
diff --git a/libs/web-components/src/components/badge/Badge.spec.ts b/libs/web-components/src/components/badge/Badge.spec.ts
index cc3ee1a7eb..dfee02d1df 100644
--- a/libs/web-components/src/components/badge/Badge.spec.ts
+++ b/libs/web-components/src/components/badge/Badge.spec.ts
@@ -115,6 +115,36 @@ describe("GoABadgeComponent", () => {
});
});
+ describe("V2 Emphasis", () => {
+ it(`should apply strong emphasis class in v2`, async () => {
+ const baseElement = render(GoABadge, {
+ testid: "badge-test",
+ type: "information",
+ content: "Strong",
+ version: "2",
+ emphasis: "strong",
+ });
+ const badge = await baseElement.findByTestId("badge-test");
+
+ expect(badge).toHaveClass("v2");
+ expect(badge).toHaveClass("badge-strong");
+ });
+
+ it(`should apply subtle emphasis class in v2`, async () => {
+ const baseElement = render(GoABadge, {
+ testid: "badge-test",
+ type: "information",
+ content: "Subtle",
+ version: "2",
+ emphasis: "subtle",
+ });
+ const badge = await baseElement.findByTestId("badge-test");
+
+ expect(badge).toHaveClass("v2");
+ expect(badge).toHaveClass("badge-subtle");
+ });
+ });
+
describe("Custom Icon Type", () => {
it(`should render custom icon type when icontype is provided`, async () => {
const result = render(GoABadge, {
@@ -159,7 +189,7 @@ describe("GoABadgeComponent", () => {
});
const badge = await result.findByTestId("badge-test");
const goaIcon = result.container.querySelector("goa-icon");
-
+
expect(goaIcon).toBeNull(); // No icon should be rendered
expect(badge).toContainHTML("No Icon");
expect(badge).toHaveClass("badge-success");
diff --git a/libs/web-components/src/components/badge/Badge.svelte b/libs/web-components/src/components/badge/Badge.svelte
index d01fb33658..4a4517bc4e 100644
--- a/libs/web-components/src/components/badge/Badge.svelte
+++ b/libs/web-components/src/components/badge/Badge.svelte
@@ -77,7 +77,11 @@
type BadgeType = (typeof Types)[number];
type BadgeSize = (typeof badgeSizes)[number];
type BadgeVersion = (typeof versions)[number];
- type BadgeJustifyContent = "center" | "flex-start" | "flex-end" | "space-between";
+ type BadgeJustifyContent =
+ | "center"
+ | "flex-start"
+ | "flex-end"
+ | "space-between";
/** Defines the context and colour of the badge. */
export let type: BadgeType;
@@ -384,6 +388,10 @@
padding-bottom: 0;
}
+ .v2.badge-strong {
+ box-shadow: none;
+ }
+
/* Version 2: Default Colours */
.v2.badge-default {
background-color: var(--goa-badge-default-color-bg);