diff --git a/.changeset/chips-component.md b/.changeset/chips-component.md
new file mode 100644
index 000000000..c3f808c1d
--- /dev/null
+++ b/.changeset/chips-component.md
@@ -0,0 +1,5 @@
+---
+'@workflowbuilder/ui': minor
+---
+
+Add the `Chip` component — a compact tag in the DS 2.0 solid and outline treatments, four sizes (`s`–`xl`), optional prefix icon and close affordance.
diff --git a/.changeset/conditions-tag-chip.md b/.changeset/conditions-tag-chip.md
new file mode 100644
index 000000000..6b9f17cde
--- /dev/null
+++ b/.changeset/conditions-tag-chip.md
@@ -0,0 +1,5 @@
+---
+'@workflowbuilder/sdk': patch
+---
+
+The dynamic-conditions counter tag is rendered with the UI `Chip` component. Same neutral surface colors; the tag gets the DS 2.0 chip metrics — 10px label (was 12px) in a 20px-tall pill with slightly tighter padding.
diff --git a/apps/docs/scripts/ui-components.mjs b/apps/docs/scripts/ui-components.mjs
index 03f4d47a1..2ca13c574 100644
--- a/apps/docs/scripts/ui-components.mjs
+++ b/apps/docs/scripts/ui-components.mjs
@@ -20,6 +20,7 @@ export const COMPONENTS = [
dir: 'button',
},
{ slug: 'checkbox', name: 'Checkbox', propsType: 'CheckboxProps', dir: 'checkbox' },
+ { slug: 'chips', name: 'Chip', propsType: 'ChipProps', dir: 'chips' },
{ slug: 'collapsible', name: 'Collapsible', propsType: 'CollapsibleProps', dir: 'collapsible' },
{ slug: 'date-picker', name: 'DatePicker', propsType: 'DatePickerProps', dir: 'date-picker' },
{ slug: 'icon-switch', name: 'IconSwitch', propsType: 'IconSwitchProps', dir: 'switch/icon-switch' },
diff --git a/apps/docs/src/components/ui-examples/chips.tsx b/apps/docs/src/components/ui-examples/chips.tsx
new file mode 100644
index 000000000..31054357e
--- /dev/null
+++ b/apps/docs/src/components/ui-examples/chips.tsx
@@ -0,0 +1,17 @@
+import { Tag } from '@phosphor-icons/react';
+import { Chip } from '@workflowbuilder/ui';
+
+import { ComponentPreview } from './component-preview';
+
+export function ChipsExample() {
+ return (
+
+
+
+
+ } />
+ {}} />
+
+
+ );
+}
diff --git a/apps/docs/src/content/docs/ui-library/ui-components/chips.mdx b/apps/docs/src/content/docs/ui-library/ui-components/chips.mdx
new file mode 100644
index 000000000..36af95b93
--- /dev/null
+++ b/apps/docs/src/content/docs/ui-library/ui-components/chips.mdx
@@ -0,0 +1,33 @@
+---
+title: Chip
+description: Compact tag for labeling and filtering, in solid and outline treatments.
+---
+
+import CssVariablesTable from '../../../../components/api/css-variables-table.astro';
+import PropsTable from '../../../../components/api/props-table.astro';
+import { ChipsExample } from '../../../../components/ui-examples/chips';
+
+A `Chip` is a compact tag in one of two treatments: `solid` on the neutral
+chip surface, or `outline` with the brand border and accent. Four sizes
+(`s`, `m`, `l`, `xl`), an optional prefix icon, and an optional close
+affordance.
+
+
+
+## Usage
+
+```tsx
+import { Chip } from '@workflowbuilder/ui';
+
+function Example() {
+ return remove()} />;
+}
+```
+
+## Props
+
+
+
+## CSS variables
+
+
diff --git a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.module.css b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.module.css
index 40681cb9b..6c0231e74 100644
--- a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.module.css
+++ b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.module.css
@@ -2,8 +2,6 @@
--wb-conditions-form-border-color: var(--ax-ui-stroke-primary-default); /* missing token */
--wb-conditions-form-border-radius: 0.75rem; /* missing token */
--wb-conditions-form-header-color: var(--ax-public-form-label-color);
-
- --wb-conditions-form-tag-bg-color: var(--ax-chips-neutral-bg);
}
.container {
@@ -27,12 +25,5 @@
}
.tag {
- composes: ax-public-p10 from global;
-
- display: inline-block;
margin-top: 0.25rem;
- padding: 0.25rem 0.5rem;
- border-radius: 0.25rem;
- background-color: var(--wb-conditions-form-tag-bg-color);
- margin-right: auto;
}
diff --git a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.tsx b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.tsx
index ef6327bab..99beb7c6f 100644
--- a/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.tsx
+++ b/packages/sdk/src/features/json-form/controls/dynamic-conditions-control/dynamic-conditions-control.tsx
@@ -1,4 +1,4 @@
-import { NavButton } from '@workflowbuilder/ui';
+import { Chip, NavButton } from '@workflowbuilder/ui';
import clsx from 'clsx';
import { useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
@@ -49,7 +49,7 @@ function DynamicConditionsControl(props: DynamicConditionsControlProps) {
- {t('totalNumber', { count: data.length })}
+
);
}
diff --git a/packages/ui/src/components/chips/chips.module.css b/packages/ui/src/components/chips/chips.module.css
new file mode 100644
index 000000000..62c4b6834
--- /dev/null
+++ b/packages/ui/src/components/chips/chips.module.css
@@ -0,0 +1,69 @@
+@layer ui.component {
+ .chip {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--wb-space-50);
+ border-radius: var(--wb-radius-50);
+ white-space: nowrap;
+ }
+
+ .solid {
+ background-color: var(--wb-components-chips-solid);
+ color: var(--wb-components-chips-solid-text);
+ }
+
+ .outline {
+ background-color: var(--wb-components-chips-inset-outline);
+ background-image: linear-gradient(
+ var(--wb-components-chips-overlay-outline),
+ var(--wb-components-chips-overlay-outline)
+ );
+ box-shadow: 0 0 0 var(--wb-size-12) var(--wb-components-chips-inset-outline);
+ color: var(--wb-components-chips-inset-outline);
+ }
+
+ .s {
+ height: 0.875rem;
+ padding-inline: var(--wb-space-50);
+ }
+
+ .m {
+ height: 1rem;
+ padding-inline: var(--wb-space-50);
+ }
+
+ .l {
+ height: 1.25rem;
+ padding-inline: var(--wb-space-75);
+ }
+
+ .xl {
+ height: 1.375rem;
+ padding-inline: var(--wb-space-75);
+ }
+
+ .icon,
+ .close {
+ display: inline-flex;
+ align-items: center;
+ }
+
+ .icon svg,
+ .close svg {
+ width: 0.625rem;
+ height: 0.625rem;
+ }
+
+ .close {
+ padding: 0;
+ border: none;
+ background: none;
+ color: inherit;
+ cursor: pointer;
+
+ &:focus-visible {
+ box-shadow: 0 0 0 2px var(--ax-focus-ring-element);
+ outline: none;
+ }
+ }
+}
diff --git a/packages/ui/src/components/chips/chips.tsx b/packages/ui/src/components/chips/chips.tsx
new file mode 100644
index 000000000..001f121b8
--- /dev/null
+++ b/packages/ui/src/components/chips/chips.tsx
@@ -0,0 +1,51 @@
+import { X } from '@phosphor-icons/react';
+import clsx from 'clsx';
+import { HTMLAttributes, ReactNode, forwardRef } from 'react';
+
+import styles from './chips.module.css';
+
+export type ChipProps = {
+ label: string;
+ /**
+ * @default 'solid'
+ */
+ variant?: ChipVariant;
+ /**
+ * @default 'm'
+ */
+ size?: ChipSize;
+ prefixIcon?: ReactNode;
+ /**
+ * When set, a close affordance is rendered and invokes this callback.
+ */
+ onClose?: () => void;
+ /**
+ * Accessible name of the close affordance.
+ * @default `Remove ${label}`
+ */
+ closeLabel?: string;
+} & HTMLAttributes;
+
+export type ChipVariant = 'solid' | 'outline';
+export type ChipSize = 's' | 'm' | 'l' | 'xl';
+
+export const Chip = forwardRef(
+ ({ label, variant = 'solid', size = 'm', prefixIcon, onClose, closeLabel, className, ...rest }, ref) => {
+ return (
+
+ {prefixIcon && {prefixIcon}}
+ {label}
+ {onClose && (
+
+ )}
+
+ );
+ },
+);
diff --git a/packages/ui/src/components/chips/index.ts b/packages/ui/src/components/chips/index.ts
new file mode 100644
index 000000000..ffd127cac
--- /dev/null
+++ b/packages/ui/src/components/chips/index.ts
@@ -0,0 +1 @@
+export * from './chips';
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
index d50590eba..932463d2c 100644
--- a/packages/ui/src/index.ts
+++ b/packages/ui/src/index.ts
@@ -8,6 +8,7 @@ export * from './components/accordion';
export * from './components/avatar';
export * from './components/button';
export * from './components/checkbox';
+export * from './components/chips';
export * from './components/collapsible';
export * from './components/date-picker';
export * from './components/edge';
diff --git a/packages/ui/src/styles/_provisional.css b/packages/ui/src/styles/_provisional.css
index 2a5a192cb..27849bc7b 100644
--- a/packages/ui/src/styles/_provisional.css
+++ b/packages/ui/src/styles/_provisional.css
@@ -19,5 +19,23 @@
--wb-font-size-300: 1.5rem;
--wb-font-size-350: 1.75rem;
--wb-font-size-400: 2rem;
+
+ --wb-radius-50: 0.25rem;
+ --wb-space-50: 0.25rem;
+ --wb-space-75: 0.375rem;
+ --wb-size-12: 0.0625rem;
+ --wb-components-chips-inset-outline: var(--ax-colors-acc1-500);
+ }
+
+ html[data-theme='light'] {
+ --wb-components-chips-solid: var(--ax-colors-gray-300);
+ --wb-components-chips-solid-text: var(--ax-colors-gray-800);
+ --wb-components-chips-overlay-outline: color-mix(in srgb, var(--ax-colors-gray-100) 85%, transparent);
+ }
+
+ html[data-theme='dark'] {
+ --wb-components-chips-solid: var(--ax-colors-gray-650);
+ --wb-components-chips-solid-text: var(--ax-colors-gray-100);
+ --wb-components-chips-overlay-outline: color-mix(in srgb, var(--ax-colors-gray-900) 75%, transparent);
}
}
diff --git a/packages/ui/vite.config.mts b/packages/ui/vite.config.mts
index dfc38300b..daf4d3cd3 100644
--- a/packages/ui/vite.config.mts
+++ b/packages/ui/vite.config.mts
@@ -19,6 +19,7 @@ const componentEntries = [
'avatar',
'button',
'checkbox',
+ 'chips',
'collapsible',
'date-picker',
'edge',