diff --git a/packages/calcite-components/src/demos/_assets/demo-theme.ts b/packages/calcite-components/src/demos/_assets/demo-theme.ts
new file mode 100644
index 00000000000..55c02899401
--- /dev/null
+++ b/packages/calcite-components/src/demos/_assets/demo-theme.ts
@@ -0,0 +1,112 @@
+/**
+ *
+ * Sets the value of a CSS variable to a test value.
+ * This is useful for testing themed components.
+ *
+ * @param token - the token as a CSS variable
+ * @returns string - the new value for the token
+ */
+export function getTokenValue(token: string): string {
+ const tokenValueMap = {
+ background$: "rgb(252, 244, 52)",
+ "text-color$": "rgb(239,118,39)",
+ "border-color$": "rgb(156, 89, 209)",
+ "background-color$": "rgb(44, 44, 44)",
+ color$: "rgb(0, 191, 255)",
+ highlighted$: "rgb(255, 105, 180)",
+ selected$: "rgb(255, 255, 255)",
+ shadow$:
+ "rgb(255, 255, 255) 0px 0px 0px 4px, rgb(255, 105, 180) 0px 0px 0px 5px inset, rgb(0, 191, 255) 0px 0px 0px 9px",
+ "z-index$": "42",
+ "(size|space)$": "42px",
+ } as const;
+
+ const match = Object.entries(tokenValueMap).find(([regexStr]) => {
+ return new RegExp(regexStr, "g").test(token);
+ });
+
+ if (!match) {
+ console.warn("token not found in tokenValueMap", token);
+ return tokenValueMap["color$"];
+ }
+
+ return match[1];
+}
+
+/*
+ * @prop tokens - an array of CSS variables
+ * @returns a string of CSS variables with their new values.
+ */
+export function setCSSVariables(tokens: string[]): string {
+ return tokens
+ .map((token) => {
+ return `${token}: ${getTokenValue(token)};`;
+ })
+ .join("\n");
+}
+
+/**
+ *
+ * @example
+ * Button
+ */
+export class DemoTheme extends HTMLElement {
+ _slot: HTMLSlotElement;
+
+ _el: HTMLElement;
+
+ static observedAttributes = ["tokens"];
+
+ constructor() {
+ super();
+ const shadow = this.attachShadow({ mode: "open" });
+ const slot = document.createElement("slot");
+ shadow.append(slot);
+ this._slot = slot;
+ if (this._slot.assignedNodes().length === 1 && this._slot.assignedNodes()[0].nodeName.includes("calcite")) {
+ this._el = this._slot.assignedNodes()[0] as HTMLElement;
+ }
+ }
+
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
+ if (newValue !== oldValue && name === "tokens") {
+ this.updateTheme(newValue);
+ }
+ }
+
+ updateTheme(newValue: string): void {
+ if (typeof newValue === "string") {
+ let tokensList;
+
+ try {
+ tokensList = JSON.parse(newValue);
+ } catch (error) {
+ tokensList = newValue.split(",").map((t) => t.trim());
+ }
+
+ if (Array.isArray(tokensList)) {
+ const stringifiedTheme = setCSSVariables(tokensList);
+
+ if (this._el) {
+ this._el.style.cssText = stringifiedTheme;
+ } else {
+ this.setAttribute("style", stringifiedTheme);
+ }
+ }
+ }
+ }
+}
+
+customElements.define("demo-theme", DemoTheme);
diff --git a/packages/calcite-components/src/demos/_assets/head.ts b/packages/calcite-components/src/demos/_assets/head.ts
index eeda4a8ab55..b82226531b6 100644
--- a/packages/calcite-components/src/demos/_assets/head.ts
+++ b/packages/calcite-components/src/demos/_assets/head.ts
@@ -18,6 +18,10 @@
{
src: "demos/_assets/demo-dom-swapper.js",
},
+ {
+ src: "demos/_assets/demo-theme.js",
+ type: "module",
+ },
];
const parseTemplate = (text: string): HTMLTemplateElement | null => {
diff --git a/packages/calcite-components/src/tests/commonTests/themed.ts b/packages/calcite-components/src/tests/commonTests/themed.ts
index 00524d01382..363577eb8f4 100644
--- a/packages/calcite-components/src/tests/commonTests/themed.ts
+++ b/packages/calcite-components/src/tests/commonTests/themed.ts
@@ -2,6 +2,7 @@ import { E2EElement, E2EPage } from "@stencil/core/testing";
import { toHaveNoViolations } from "jest-axe";
import { ElementHandle } from "puppeteer";
import type { RequireExactlyOne } from "type-fest";
+import { getTokenValue } from "../utils/cssTokenValues";
import type { ComponentTestSetup } from "./interfaces";
import { getTagAndPage } from "./utils";
@@ -101,7 +102,7 @@ export function themed(componentTestSetup: ComponentTestSetup, tokens: Component
// Set test values for each token
if (!setTokens[token]) {
- setTokens[token] = assignTestTokenThemeValues(token);
+ setTokens[token] = getTokenValue(token);
}
// Set up styleTargets and testTargets
@@ -426,21 +427,3 @@ async function assertThemedProps(page: E2EPage, options: TestTarget): Promise {
+ return new RegExp(regexStr, "g").test(token);
+ });
+
+ if (!match) {
+ console.warn("token not found in tokenValueMap", token);
+ return tokenValueMap["color$"];
+ }
+
+ return match[1];
+}
+
+/**
+ *
+ * @param tokens - an array of CSS variables
+ * @returns a string of CSS variables with their new values.
+ */
+export function setCSSVariables(tokens: string[]): string {
+ return tokens
+ .map((token) => {
+ return `${token}: ${getTokenValue(token)};`;
+ })
+ .join("\n");
+}