From ad6372df59cdcd9f4009bd8eb9f67e9e7748d3e8 Mon Sep 17 00:00:00 2001
From: Nathnael Dereje
Date: Thu, 1 Oct 2026 10:21:30 +0200
Subject: [PATCH 01/12] feat: Add prefix and secondaryText to Token
Add a prefix slot before the label (for example a category color dot) and a secondaryText value after it. Includes a Token additions dev page demoing both, plus popover composition in the label slot.
---
pages/token/additions.page.tsx | 263 +++++++++++++++++++++++++++++++++
pages/token/styles.scss | 65 ++++++++
src/token/interfaces.ts | 13 ++
src/token/internal.tsx | 12 ++
src/token/styles.scss | 15 ++
5 files changed, 368 insertions(+)
create mode 100644 pages/token/additions.page.tsx
diff --git a/pages/token/additions.page.tsx b/pages/token/additions.page.tsx
new file mode 100644
index 0000000000..d7bb592d51
--- /dev/null
+++ b/pages/token/additions.page.tsx
@@ -0,0 +1,263 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+import React from 'react';
+
+import Box from '~components/box';
+import CopyToClipboard from '~components/copy-to-clipboard';
+import ExpandableSection from '~components/expandable-section';
+import Icon, { IconProps } from '~components/icon';
+import Popover from '~components/popover';
+import SpaceBetween from '~components/space-between';
+import Token, { TokenProps } from '~components/token';
+import { colorChartsPaletteCategorical2 } from '~design-tokens';
+
+import styles from './styles.scss';
+
+// Colors are consumer-owned: the token provides the prefix slot, the consuming team
+// chooses the visual (per the kickoff). A real console would use its own design tokens.
+const RED = '#d13212';
+const ORANGE = '#ec7211';
+const YELLOW = '#f2c811';
+const GREEN = '#1d8102';
+const BLUE = '#0972d3';
+const PURPLE = '#7d4bcb';
+
+function Dot({ color }: { color: string }) {
+ return ;
+}
+
+function QueryAction({ icon, label }: { icon: IconProps.Name; label: string }) {
+ return (
+
+
+
+ {label}
+
+
+
+ );
+}
+
+function SectionLabel({ text, counter }: { text: string; counter?: string }) {
+ return (
+
+ {text}
+ {counter && {counter}}
+
+ );
+}
+
+// Mirrors the CloudWatch Log Analytics field-details popover: field name + copy + category
+// token header, coverage bar in the category color, then log groups and query actions.
+function FieldDetails({ field, category, color }: { field: string; category: string; color: string }) {
+ return (
+
A secondary value next to the label, such as coverage or a count.
+
Label tag
+
+ The existing labelTag prop, now also shown for the inline variant, for values such as coverage or a count.
+
With percentage
With color, icon, and count
@@ -239,14 +241,14 @@ export default function TokenAdditionsPage() {
Clicking the label opens a popover with contextual actions. Composed by passing Popover in the label slot,
no dedicated prop.
-
Field details with prefix and secondary text
+
Field details with prefix and label tag
Inline
-
With prefix and secondary text
-
+
With prefix and label tag
+
diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
index 6d91b4bcbe..4823100ea3 100644
--- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
+++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
@@ -33723,12 +33723,6 @@ use the \`id\` attribute, consider setting it on a parent element instead.",
"optional": true,
"type": "boolean",
},
- {
- "description": "Secondary text shown inline after the label, such as a count or percentage.",
- "name": "secondaryText",
- "optional": true,
- "type": "string",
- },
{
"description": "An object containing CSS properties to customize the token's visual appearance.
Refer to the [style](/components/token/?tabId=style) tab for more details.",
@@ -33913,7 +33907,7 @@ Only applies to plain text labels.",
{
"description": "Specifies the token's visual style and functionality.
-For \`inline\` only label, icon and dismiss button are displayed.
+For \`inline\` only label, label tag, icon and dismiss button are displayed.
Defaults to \`normal\` if not specified.",
"inlineType": {
diff --git a/src/token/__tests__/token.test.tsx b/src/token/__tests__/token.test.tsx
index 0808b3b842..176011fbb3 100644
--- a/src/token/__tests__/token.test.tsx
+++ b/src/token/__tests__/token.test.tsx
@@ -162,6 +162,35 @@ describe('Token', () => {
});
});
+ describe('Prefix', () => {
+ test('renders prefix in an aria-hidden slot', () => {
+ const wrapper = renderToken({
+ label: 'Test token',
+ prefix: ,
+ });
+ const prefix = wrapper.findByClassName(styles.prefix)!.getElement();
+ expect(prefix).toHaveAttribute('aria-hidden', 'true');
+ expect(prefix).toContainElement(screen.getByTestId('prefix-dot'));
+ });
+
+ test('does not render prefix slot when prefix is not set', () => {
+ const wrapper = renderToken({ label: 'Test token' });
+ expect(wrapper.findByClassName(styles.prefix)).toBeNull();
+ });
+ });
+
+ describe('Label tag', () => {
+ test('renders label tag for normal variant', () => {
+ const wrapper = renderToken({ label: 'Test token', labelTag: '17%' });
+ expect(wrapper.findLabelTag()!.getElement()).toHaveTextContent('17%');
+ });
+
+ test('renders label tag for inline variant', () => {
+ const wrapper = renderToken({ label: 'Test token', variant: 'inline', labelTag: '17%' });
+ expect(wrapper.findLabelTag()!.getElement()).toHaveTextContent('17%');
+ });
+ });
+
describe('One theme', () => {
beforeEach(() => {
document.body.classList.add('awsui-one-theme');
diff --git a/src/token/interfaces.ts b/src/token/interfaces.ts
index db2dbde1a6..c6b08e6be1 100644
--- a/src/token/interfaces.ts
+++ b/src/token/interfaces.ts
@@ -39,7 +39,7 @@ export interface TokenProps extends BaseComponentProps {
/**
* Specifies the token's visual style and functionality.
*
- * For `inline` only label, icon and dismiss button are displayed.
+ * For `inline` only label, label tag, icon and dismiss button are displayed.
*
* Defaults to `normal` if not specified.
*/
@@ -71,11 +71,6 @@ export interface TokenProps extends BaseComponentProps {
*/
prefix?: React.ReactNode;
- /**
- * Secondary text shown inline after the label, such as a count or percentage.
- */
- secondaryText?: string;
-
/**
* Content to display in the tooltip when `variant="inline"`. The tooltip appears when the token label is truncated due to insufficient space.
*
diff --git a/src/token/internal.tsx b/src/token/internal.tsx
index 753cc16440..048bd973ed 100644
--- a/src/token/internal.tsx
+++ b/src/token/internal.tsx
@@ -64,7 +64,6 @@ function InternalToken({
onDismiss,
tooltipContent,
prefix,
- secondaryText,
// Internal
role,
@@ -126,6 +125,7 @@ function InternalToken({
return {
...labelObject,
disabled,
+ labelTag,
__customIcon: icon && {sizedIcon(icon)},
};
} else {
@@ -208,11 +208,6 @@ function InternalToken({
labelId={ariaLabelledbyId}
customContent={__customContent}
/>
- {secondaryText !== undefined && (
-
- {secondaryText}
-
- )}
{onDismiss && (
Date: Thu, 1 Oct 2026 15:39:15 +0200
Subject: [PATCH 05/12] fix: Add ariaLabel to popover tokens on additions page
---
pages/token/additions.page.tsx | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pages/token/additions.page.tsx b/pages/token/additions.page.tsx
index 12e362c07d..4a40da36fc 100644
--- a/pages/token/additions.page.tsx
+++ b/pages/token/additions.page.tsx
@@ -158,6 +158,7 @@ function Tokens({
2. Popover token - contextual actions
Date: Thu, 1 Oct 2026 15:42:58 +0200
Subject: [PATCH 06/12] chore: Use text-inline popover trigger for inline
tokens
---
pages/token/additions.page.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/pages/token/additions.page.tsx b/pages/token/additions.page.tsx
index 4a40da36fc..b5aa0899c5 100644
--- a/pages/token/additions.page.tsx
+++ b/pages/token/additions.page.tsx
@@ -162,6 +162,7 @@ function Tokens({
label={
}
>
From 9a554149717d1ba6298a228fcca34057309ce569 Mon Sep 17 00:00:00 2001
From: Nathnael Dereje
Date: Mon, 5 Oct 2026 17:43:27 +0200
Subject: [PATCH 07/12] refactor: Drop Token prefix slot, use icon for color
dots
Color dots are a custom icon, so they go through the existing icon slot instead of a new prefix prop. The dev page now passes the dot as icon.
---
pages/token/additions.page.tsx | 34 ++++++++++++-------
pages/token/styles.scss | 9 +++++
.../__snapshots__/documenter.test.ts.snap | 8 -----
src/token/__tests__/token.test.tsx | 17 ----------
src/token/interfaces.ts | 8 -----
src/token/internal.tsx | 6 ----
src/token/styles.scss | 8 -----
7 files changed, 30 insertions(+), 60 deletions(-)
diff --git a/pages/token/additions.page.tsx b/pages/token/additions.page.tsx
index b5aa0899c5..c9bcd62cb9 100644
--- a/pages/token/additions.page.tsx
+++ b/pages/token/additions.page.tsx
@@ -13,8 +13,8 @@ import { colorChartsPaletteCategorical2 } from '~design-tokens';
import styles from './styles.scss';
-// Colors are consumer-owned: the token provides the prefix slot, the consuming team
-// chooses the visual (per the kickoff). A real console would use its own design tokens.
+// A color dot is a custom icon passed through the existing icon slot. Colors are consumer-owned;
+// a real console would use its own design tokens.
const RED = '#d13212';
const ORANGE = '#ec7211';
const YELLOW = '#f2c811';
@@ -23,7 +23,11 @@ const BLUE = '#0972d3';
const PURPLE = '#7d4bcb';
function Dot({ color }: { color: string }) {
- return ;
+ return (
+
+
+
+ );
}
function QueryAction({ icon, label }: { icon: IconProps.Name; label: string }) {
@@ -63,7 +67,7 @@ function FieldDetails({ field, category, color }: { field: string; category: str
copyErrorText={`Failed to copy ${field}`}
/>
- } />
+ } />
- A color dot marks a category, passed via the prefix slot. Always paired with a label, never color alone.
+ A color dot marks a category, passed as a custom icon through the icon slot. Always paired with a label,
+ never color alone.
With dismiss
@@ -234,7 +242,7 @@ export default function TokenAdditionsPage() {
With percentage
-
With color, icon, and count
+
With icon and count
@@ -244,13 +252,13 @@ export default function TokenAdditionsPage() {
Clicking the label opens a popover with contextual actions. Composed by passing Popover in the label slot,
no dedicated prop.
-
Field details with prefix and label tag
+
Field details with color dot icon and label tag
Inline
-
With prefix and label tag
+
With color dot icon and label tag
diff --git a/pages/token/styles.scss b/pages/token/styles.scss
index 397c758264..460f1c1968 100644
--- a/pages/token/styles.scss
+++ b/pages/token/styles.scss
@@ -35,6 +35,15 @@
border-end-end-radius: 50%;
}
+// Gives the dot the same 16px box as a normal-size Icon, so it lines up in the token's icon slot.
+.dot-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ inline-size: 16px;
+ block-size: 16px;
+}
+
.field-details {
inline-size: 320px;
}
diff --git a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
index 4823100ea3..40cd7e37a0 100644
--- a/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
+++ b/src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
@@ -33940,14 +33940,6 @@ For \`variant="inline"\`, only plain text is supported, for example, strings or
"isDefault": false,
"name": "label",
},
- {
- "description": "Slot for a decorative category marker before the label, typically a color dot.
-
-The slot is \`aria-hidden\` and must not contain interactive content. Convey the category
-in the \`label\` or \`ariaLabel\` as well - color must never be the only signal.",
- "isDefault": false,
- "name": "prefix",
- },
],
"releaseStatus": "stable",
}
diff --git a/src/token/__tests__/token.test.tsx b/src/token/__tests__/token.test.tsx
index 176011fbb3..b31d2f8e56 100644
--- a/src/token/__tests__/token.test.tsx
+++ b/src/token/__tests__/token.test.tsx
@@ -162,23 +162,6 @@ describe('Token', () => {
});
});
- describe('Prefix', () => {
- test('renders prefix in an aria-hidden slot', () => {
- const wrapper = renderToken({
- label: 'Test token',
- prefix: ,
- });
- const prefix = wrapper.findByClassName(styles.prefix)!.getElement();
- expect(prefix).toHaveAttribute('aria-hidden', 'true');
- expect(prefix).toContainElement(screen.getByTestId('prefix-dot'));
- });
-
- test('does not render prefix slot when prefix is not set', () => {
- const wrapper = renderToken({ label: 'Test token' });
- expect(wrapper.findByClassName(styles.prefix)).toBeNull();
- });
- });
-
describe('Label tag', () => {
test('renders label tag for normal variant', () => {
const wrapper = renderToken({ label: 'Test token', labelTag: '17%' });
diff --git a/src/token/interfaces.ts b/src/token/interfaces.ts
index c6b08e6be1..7dc65af2d7 100644
--- a/src/token/interfaces.ts
+++ b/src/token/interfaces.ts
@@ -63,14 +63,6 @@ export interface TokenProps extends BaseComponentProps {
*/
onDismiss?: NonCancelableEventHandler;
- /**
- * Slot for a decorative category marker before the label, typically a color dot.
- *
- * The slot is `aria-hidden` and must not contain interactive content. Convey the category
- * in the `label` or `ariaLabel` as well - color must never be the only signal.
- */
- prefix?: React.ReactNode;
-
/**
* Content to display in the tooltip when `variant="inline"`. The tooltip appears when the token label is truncated due to insufficient space.
*
diff --git a/src/token/internal.tsx b/src/token/internal.tsx
index 048bd973ed..81268c396a 100644
--- a/src/token/internal.tsx
+++ b/src/token/internal.tsx
@@ -63,7 +63,6 @@ function InternalToken({
dismissLabel,
onDismiss,
tooltipContent,
- prefix,
// Internal
role,
@@ -193,11 +192,6 @@ function InternalToken({
)}
style={tokenRootStyleProps}
>
- {prefix && (
-
- {prefix}
-
- )}