diff --git a/labs/gb/components/chip/_chip-tokens.scss b/labs/gb/components/chip/_chip-tokens.scss
new file mode 100644
index 0000000000..3a30d901f6
--- /dev/null
+++ b/labs/gb/components/chip/_chip-tokens.scss
@@ -0,0 +1,167 @@
+//
+// Copyright 2026 Google LLC
+// SPDX-License-Identifier: Apache-2.0
+//
+
+// Auto-generated by cascade_tokens
+// Add `// EDIT:` comments for manual adjustments.
+//
+// --prefix=md.comp.chip
+// --states="hovered|focused|pressed|dragged,:unselected|selected,:filter|input,with-leading-icon|with-avatar,with-trailing-icon,disabled"
+// --exclude=motion,state-layer,indicator
+
+@mixin root {
+ // LINT.IfChange
+ --avatar-opacity: unset;
+ // md.comp.chip.avatar.shape
+ --avatar-shape: var(--md-sys-shape-corner-full);
+ // md.comp.chip.avatar.size
+ --avatar-size: 24px;
+ --container-color: unset;
+ // md.comp.chip.container.elevation
+ --container-elevation: var(--md-sys-elevation-shadow-0);
+ // --container-opacity: unset; // EDIT: unused
+ // md.comp.chip.gap.horizontal
+ --gap-horizontal: var(--md-sys-space-50);
+ // md.comp.chip.height
+ --height: 32px;
+ // md.comp.chip.label-text
+ --label-text: var(--md-sys-typescale-label-lg);
+ // ┌┄ md.comp.chip.label-text
+ --label-text-axes: var(--md-sys-typescale-label-lg-axes);
+ // md.comp.chip.unselected.label-text.color
+ --label-text-color: var(--md-sys-color-on-surface-variant);
+ // --label-text-opacity: unset; // EDIT: unused
+ // ┌┄ md.comp.chip.label-text
+ --label-text-tracking: var(--md-sys-typescale-label-lg-tracking);
+ // md.comp.chip.unselected.leading-icon.color
+ --leading-icon-color: var(--md-sys-color-on-surface-variant);
+ // --leading-icon-opacity: unset; // EDIT: unused
+ // md.comp.chip.leading-icon.size
+ --leading-icon-size: 18px;
+ // md.comp.chip.unselected.outline.color
+ --outline-color: var(--md-sys-color-outline-variant);
+ // --outline-opacity: unset; // EDIT: unused
+ // md.comp.chip.unselected.outline.width
+ --outline-width: 1px;
+ // md.comp.chip.padding.bottom
+ --padding-bottom: var(--md-sys-space-75);
+ // ┌ md.comp.chip.filter.padding.leading
+ --padding-leading: var(--md-sys-space-200);
+ // md.comp.chip.padding.top
+ --padding-top: var(--md-sys-space-75);
+ // ┌ md.comp.chip.filter.padding.trailing
+ --padding-trailing: var(--md-sys-space-200);
+ // md.comp.chip.unselected.shape
+ --shape: var(--md-sys-shape-corner-md);
+ // md.comp.chip.unselected.trailing-icon.color
+ --trailing-icon-color: var(--md-sys-color-on-surface-variant);
+ // --trailing-icon-opacity: unset; // EDIT: unused
+ // md.comp.chip.trailing-icon.size
+ --trailing-icon-size: 18px;
+ // LINT.ThenChange(md-gb-chip.ts) sync with `@cssprop` jsdoc tags
+}
+
+@mixin pressed {
+ // md.comp.chip.pressed.shape
+ --shape: var(--md-sys-shape-corner-sm);
+}
+
+@mixin dragged {
+ // md.comp.chip.dragged.container.elevation
+ --container-elevation: var(--md-sys-elevation-shadow-4);
+}
+
+@mixin selected {
+ // md.comp.chip.selected.container.color
+ --container-color: var(--md-sys-color-secondary-container);
+ // md.comp.chip.selected.label-text.color
+ --label-text-color: var(--md-sys-color-on-secondary-container);
+ // md.comp.chip.selected.leading-icon.color
+ --leading-icon-color: var(--md-sys-color-on-secondary-container);
+ // md.comp.chip.selected.outline.width
+ --outline-width: 0px;
+ // md.comp.chip.selected.shape
+ --shape: var(--md-sys-shape-corner-full);
+ // md.comp.chip.selected.trailing-icon.color
+ --trailing-icon-color: var(--md-sys-color-on-secondary-container);
+}
+
+@mixin input {
+ // md.comp.chip.input.padding.leading
+ --padding-leading: var(--md-sys-space-150);
+ // md.comp.chip.input.padding.trailing
+ --padding-trailing: var(--md-sys-space-150);
+}
+
+@mixin with-leading-icon {
+ // md.comp.chip.with-leading-icon.padding.leading
+ --padding-leading: var(--md-sys-space-100);
+}
+
+@mixin with-avatar {
+ // md.comp.chip.with-avatar.padding.leading
+ --padding-leading: var(--md-sys-space-50);
+}
+
+@mixin with-trailing-icon {
+ // md.comp.chip.with-trailing-icon.padding.trailing
+ --padding-trailing: var(--md-sys-space-100);
+}
+
+@mixin disabled {
+ // md.comp.chip.disabled.avatar.opacity
+ --avatar-opacity: 0.38;
+ // ┌ md.comp.chip.disabled.label-text.opacity
+ // md.comp.chip.disabled.label-text.color
+ --label-text-color: hsl(from var(--md-sys-color-on-surface) h s l / 0.38);
+ // ┌ md.comp.chip.disabled.leading-icon.opacity
+ // md.comp.chip.disabled.leading-icon.color
+ --leading-icon-color: hsl(from var(--md-sys-color-on-surface) h s l / 0.38);
+ // ┌ md.comp.chip.unselected.disabled.outline.opacity
+ // md.comp.chip.unselected.disabled.outline.color
+ --outline-color: hsl(from var(--md-sys-color-on-surface) h s l / 0.1);
+ // ┌ md.comp.chip.disabled.trailing-icon.opacity
+ // md.comp.chip.disabled.trailing-icon.color
+ --trailing-icon-color: hsl(from var(--md-sys-color-on-surface) h s l / 0.38);
+}
+
+@mixin disabled-selected {
+ // ┌ md.comp.chip.selected.disabled.container.opacity
+ // md.comp.chip.selected.disabled.container.color
+ --container-color: hsl(from var(--md-sys-color-on-surface) h s l / 0.12);
+}
+
+// EDIT: Manual adjustments
+@mixin filter {
+ // Hoisted to root, so empty here to satisfy chip.scss mapping
+}
+
+@mixin elevated {
+ --container-color: var(--md-sys-color-surface-container-low);
+ --container-elevation: var(--md-sys-elevation-shadow-1);
+ --label-text-color: var(--md-sys-color-on-surface);
+ --outline-width: 0;
+}
+
+@mixin filled {
+ --container-color: var(--md-sys-color-surface-container);
+ --container-elevation: var(--md-sys-elevation-shadow-0);
+ --label-text-color: var(--md-sys-color-on-surface);
+ --outline-width: 0;
+}
+
+@mixin tonal {
+ --container-color: var(--md-sys-color-secondary-container);
+ --container-elevation: var(--md-sys-elevation-shadow-0);
+ --label-text-color: var(--md-sys-color-on-secondary-container);
+ --outline-width: 0;
+}
+
+@mixin outlined {
+ --container-color: transparent;
+ --container-elevation: var(--md-sys-elevation-shadow-0);
+ --label-text-color: var(--md-sys-color-on-surface);
+ --outline-color: var(--md-sys-color-outline);
+ --outline-width: 1px;
+}
diff --git a/labs/gb/components/chip/chip-element.ts b/labs/gb/components/chip/chip-element.ts
new file mode 100644
index 0000000000..a593797d0e
--- /dev/null
+++ b/labs/gb/components/chip/chip-element.ts
@@ -0,0 +1,222 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {css, CSSResultOrNative, html, LitElement, nothing} from 'lit';
+import {property, state} from 'lit/decorators.js';
+import {redispatchEvent} from '../../../../internal/events/redispatch-event.js';
+import focusRingStyles from '../focus/focus-ring.cssresult.js';
+import rippleStyles from '../ripple/ripple.cssresult.js';
+import {chip, type ChipColor, type ChipType} from './chip.js';
+import {styles as chipStyles} from './chip.cssresult.js';
+
+/**
+ * A Material Design Expressive Chip component (`md-gb-chip`).
+ *
+ * @slot - Used to display the chip label text.
+ * @slot icon - Used to display an optional leading icon, checkmark, or avatar.
+ * @slot remove-icon - Used to display the trailing remove button icon when `removable="true"`.
+ * @fires {Event} remove - Fired when the remove action is triggered on a removable chip. --bubbles --composed
+ * @fires {Event} change - Fired when a filter/toggle chip's selection state changes. --bubbles
+ * @fires {InputEvent} input - Fired when a filter/toggle chip's selection state changes. --bubbles --composed
+ * @csspart chip - The root container element.
+ * @cssprop --avatar-opacity
+ * @cssprop --avatar-shape
+ * @cssprop --avatar-size
+ * @cssprop --container-color
+ * @cssprop --container-elevation
+ * @cssprop --container-opacity
+ * @cssprop --gap-horizontal
+ * @cssprop --height
+ * @cssprop --label-text
+ * @cssprop --label-text-color
+ * @cssprop --label-text-opacity
+ * @cssprop --leading-icon-color
+ * @cssprop --leading-icon-opacity
+ * @cssprop --leading-icon-size
+ * @cssprop --outline-color
+ * @cssprop --outline-opacity
+ * @cssprop --outline-width
+ * @cssprop --padding-bottom
+ * @cssprop --padding-leading
+ * @cssprop --padding-top
+ * @cssprop --padding-trailing
+ * @cssprop --shape
+ * @cssprop --trailing-icon-color
+ * @cssprop --trailing-icon-opacity
+ * @cssprop --trailing-icon-size
+ */
+export class ChipElement extends LitElement {
+ static override styles: CSSResultOrNative[] = [
+ focusRingStyles,
+ rippleStyles,
+ chipStyles,
+ css`
+ :host {
+ display: inline-flex;
+ vertical-align: middle;
+ }
+ .chip {
+ flex: 1;
+ }
+ .chip-icon {
+ display: inline-flex;
+ align-items: center;
+ }
+ `,
+ ];
+
+ /** The color emphasis of the chip. Defaults to `outlined`. */
+ @property() color: ChipColor = 'outlined';
+
+ /** The functional behavior type of the chip (`action`, `filter`, `toggle`, `link`). */
+ @property() type: ChipType = 'action';
+
+ /** Whether the filter or toggle chip is selected. */
+ @property({type: Boolean, reflect: true}) selected = false;
+
+ /** Whether the chip is removable. */
+ @property({type: Boolean, reflect: true}) removable = false;
+
+ /** Whether the chip is disabled. */
+ @property({type: Boolean, reflect: true}) disabled = false;
+
+ /** Whether the chip is soft-disabled (`aria-disabled="true"` while preserving focusability). */
+ @property({type: Boolean, attribute: 'soft-disabled', reflect: true})
+ softDisabled = false;
+
+ /** The URL destination if `type="link"` or if `href` is set. */
+ @property() href = '';
+
+ /** Where to display the linked `href` URL for a link chip. */
+ @property() target: '_blank' | '_parent' | '_self' | '_top' | '' = '';
+
+ @state() private hasLeadingIcon = false;
+ @state() private hasAvatar = false;
+ @state() private hasRemoveIcon = false;
+
+ protected override render() {
+ const isFilterSelected =
+ (this.type === 'filter' || this.type === 'toggle') && this.selected;
+ const withLeadingIcon = this.hasLeadingIcon || isFilterSelected;
+ const withAvatar = this.hasAvatar;
+
+ const chipClasses = chip({
+ color: this.color,
+ type: this.href ? 'link' : this.type,
+ selected: this.selected,
+ removable: this.removable,
+ disabled: this.softDisabled || this.disabled,
+ withLeadingIcon: withLeadingIcon && !withAvatar,
+ withAvatar,
+ withTrailingIcon: this.removable || this.hasRemoveIcon,
+ });
+
+ if (this.href || this.type === 'link') {
+ return html`
+ ${this.renderContent(withLeadingIcon, isFilterSelected)}
+ `;
+ }
+
+ if (this.removable) {
+ return html`
+
+ ${this.renderRemoveButton()}
+
`;
+ }
+
+ return html``;
+ }
+
+ private renderContent(withLeadingIcon: boolean, isFilterSelected: boolean) {
+ return html`
+ ${this.renderLeadingIcon(withLeadingIcon, isFilterSelected)}
+
+ `;
+ }
+
+ private renderLeadingIcon(
+ withLeadingIcon: boolean,
+ isFilterSelected: boolean,
+ ) {
+ return html`
+
+ ${isFilterSelected ? html`✓` : nothing}
+
+ `;
+ }
+
+ private renderRemoveButton() {
+ return html``;
+ }
+
+ private handleIconSlotChange(event: Event) {
+ const slot = event.target as HTMLSlotElement;
+ const elements = slot.assignedElements({flatten: true});
+ this.hasLeadingIcon = elements.length > 0;
+ this.hasAvatar = elements.some((el) => el.classList.contains('chip-avatar'));
+ }
+
+ private handleRemoveIconSlotChange(event: Event) {
+ const slot = event.target as HTMLSlotElement;
+ this.hasRemoveIcon = slot.assignedNodes({flatten: true}).length > 0;
+ }
+
+ private handleChange(event: Event) {
+ this.selected = (event.target as HTMLElement).ariaPressed === 'true';
+ redispatchEvent(this, event);
+ }
+
+ private handleRemove(event: Event) {
+ event.stopPropagation();
+ if (this.disabled || this.softDisabled) return;
+ this.dispatchEvent(new Event('remove', {bubbles: true, composed: true}));
+ }
+}
diff --git a/labs/gb/components/chip/chip.scss b/labs/gb/components/chip/chip.scss
new file mode 100644
index 0000000000..9ec20c9cbe
--- /dev/null
+++ b/labs/gb/components/chip/chip.scss
@@ -0,0 +1,97 @@
+/*!
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// go/keep-sorted start by_regex='(.+) prefix_order=sass:
+@use 'chip-tokens';
+// go/keep-sorted end
+
+@layer md.sys, md.comp.ripple, md.comp.focus-ring;
+@layer md.comp.chip {
+ .chip {
+ @include chip-tokens.root;
+ &.chip-elevated {
+ @include chip-tokens.elevated;
+ }
+ &.chip-filled {
+ @include chip-tokens.filled;
+ }
+ &.chip-tonal {
+ @include chip-tokens.tonal;
+ }
+ &.chip-outlined {
+ @include chip-tokens.outlined;
+ }
+ &:is(.chip-selected, [aria-pressed='true']) {
+ @include chip-tokens.selected;
+ }
+ &.chip-filter {
+ @include chip-tokens.filter;
+ }
+ &.chip-input {
+ @include chip-tokens.input;
+ }
+ &.chip-with-leading-icon {
+ @include chip-tokens.with-leading-icon;
+ }
+ &.chip-with-trailing-icon {
+ @include chip-tokens.with-trailing-icon;
+ }
+ &.chip-with-avatar {
+ @include chip-tokens.with-avatar;
+ }
+ &:is(:disabled, .disabled, [aria-disabled='true']) {
+ @include chip-tokens.disabled;
+ }
+
+ & {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ height: var(--height);
+ gap: var(--gap-horizontal);
+ padding-inline: var(--padding-leading) var(--padding-trailing);
+ padding-block: var(--padding-top) var(--padding-bottom);
+ border: var(--outline-width) solid var(--outline-color);
+ border-radius: var(--shape);
+ box-shadow: var(--container-elevation);
+ background-color: var(--container-color);
+ color: var(--label-text-color);
+ font: var(--label-text);
+ box-sizing: border-box;
+ user-select: none;
+ white-space: nowrap;
+ --md-icon-color: var(--leading-icon-color);
+ --md-icon-size: var(--leading-icon-size);
+ }
+ &:not(:disabled, .disabled, [aria-disabled='true']) {
+ cursor: pointer;
+ }
+
+ .chip-action,
+ .chip-remove {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--gap-horizontal);
+ background: transparent;
+ border: none;
+ outline: none;
+ color: inherit;
+ font: inherit;
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ cursor: inherit;
+ }
+ .chip-remove {
+ border-radius: 50%;
+ aspect-ratio: 1;
+ margin-inline-start: 4px;
+ outline: var(--focus-ring-outline);
+ --md-icon-color: var(--trailing-icon-color);
+ --md-icon-size: var(--trailing-icon-size);
+ }
+ }
+}
diff --git a/labs/gb/components/chip/chip.ts b/labs/gb/components/chip/chip.ts
new file mode 100644
index 0000000000..5b77452495
--- /dev/null
+++ b/labs/gb/components/chip/chip.ts
@@ -0,0 +1,157 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {type ClassInfo} from 'lit/directives/class-map.js';
+import {
+ afterDispatch,
+ setupDispatchHooks,
+} from '../../../../internal/events/dispatch-hooks.js';
+import {focusRingClasses} from '../focus/focus-ring.js';
+import {rippleClasses, setupRipple} from '../ripple/ripple.js';
+import {createClassMapDirective} from '../shared/directives.js';
+import {isDisabled, PSEUDO_CLASSES} from '../shared/pseudo-classes.js';
+
+/** Chip color/emphasis configuration types. */
+export type ChipColor = 'elevated' | 'filled' | 'outlined' | 'tonal';
+
+/** Chip color configurations. */
+export const CHIP_COLORS = {
+ elevated: 'elevated',
+ filled: 'filled',
+ outlined: 'outlined',
+ tonal: 'tonal',
+} as const;
+
+/** Chip functional type. */
+export type ChipType = 'action' | 'filter' | 'toggle' | 'link';
+
+/** Chip classes. */
+export const CHIP_CLASSES = {
+ chip: 'chip',
+ chipElevated: 'chip-elevated',
+ chipFilled: 'chip-filled',
+ chipOutlined: 'chip-outlined',
+ chipTonal: 'chip-tonal',
+ chipSelected: 'chip-selected',
+ chipFilter: 'chip-filter',
+ chipInput: 'chip-input',
+ chipRemovable: 'chip-removable',
+ chipWithLeadingIcon: 'chip-with-leading-icon',
+ chipWithTrailingIcon: 'chip-with-trailing-icon',
+ chipWithAvatar: 'chip-with-avatar',
+ disabled: PSEUDO_CLASSES.disabled,
+} as const;
+
+/** The state provided to the `chipClasses()` function. */
+export interface ChipClassesState {
+ /** The emphasis color of the chip. */
+ color?: ChipColor;
+ /** The functional behavior type of the chip (`action`, `filter`, `toggle`, `link`). */
+ type?: ChipType;
+ /** Whether the filter or toggle chip is selected. */
+ selected?: boolean;
+ /** Whether the chip is removable (`removable="true"`). */
+ removable?: boolean;
+ /** Whether the chip has a leading icon. */
+ withLeadingIcon?: boolean;
+ /** Whether the chip has a trailing icon. */
+ withTrailingIcon?: boolean;
+ /** Whether the chip has an avatar. */
+ withAvatar?: boolean;
+ /** Emulates `:disabled`. */
+ disabled?: boolean;
+}
+
+/**
+ * Returns the chip classes to apply to an element based on the given state.
+ *
+ * @param state The state of the chip.
+ * @return An object of class names and truthy values if they apply.
+ */
+export function chipClasses({
+ color = 'outlined',
+ type = 'action',
+ selected = false,
+ removable = false,
+ withLeadingIcon = false,
+ withTrailingIcon = false,
+ withAvatar = false,
+ disabled = false,
+}: ChipClassesState = {}): ClassInfo {
+ return {
+ ...rippleClasses(),
+ ...focusRingClasses(),
+ [CHIP_CLASSES.chip]: true,
+ [CHIP_CLASSES.chipElevated]: color === CHIP_COLORS.elevated,
+ [CHIP_CLASSES.chipFilled]: color === CHIP_COLORS.filled,
+ [CHIP_CLASSES.chipOutlined]: color === CHIP_COLORS.outlined,
+ [CHIP_CLASSES.chipTonal]: color === CHIP_COLORS.tonal,
+ [CHIP_CLASSES.chipSelected]: selected,
+ [CHIP_CLASSES.chipFilter]: type === 'filter' || type === 'toggle',
+ [CHIP_CLASSES.chipInput]: removable || type === 'action',
+ [CHIP_CLASSES.chipRemovable]: removable,
+ [CHIP_CLASSES.chipWithLeadingIcon]: withLeadingIcon,
+ [CHIP_CLASSES.chipWithTrailingIcon]: withTrailingIcon,
+ [CHIP_CLASSES.chipWithAvatar]: withAvatar,
+ [CHIP_CLASSES.disabled]: disabled,
+ };
+}
+
+/**
+ * Sets up chip functionality for the given element.
+ *
+ * @param chip The element on which to set up chip functionality.
+ * @param opts Setup options, supports a cleanup `signal`.
+ */
+export function setupChip(
+ chip: HTMLElement,
+ opts?: {signal?: AbortSignal},
+): void {
+ setupDispatchHooks(chip, 'click');
+ setupRipple(chip, opts);
+ chip.addEventListener(
+ 'click',
+ (event) => {
+ if (isDisabled(chip)) {
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ return;
+ }
+
+ afterDispatch(event, () => {
+ const isToggle =
+ chip.hasAttribute('aria-pressed') ||
+ chip.matches(
+ `.${CHIP_CLASSES.chipFilter},.${CHIP_CLASSES.chipSelected}`,
+ );
+ if (event.defaultPrevented || !isToggle) {
+ return;
+ }
+
+ const isPressed = chip.ariaPressed === 'true';
+ chip.ariaPressed = String(!isPressed);
+ chip.dispatchEvent(
+ new InputEvent('input', {bubbles: true, composed: true}),
+ );
+ chip.dispatchEvent(new Event('change', {bubbles: true}));
+ });
+ },
+ opts,
+ );
+}
+
+/**
+ * A Lit directive that adds chip styling and functionality to its element.
+ *
+ * @example
+ * ```ts
+ * html``;
+ * ```
+ */
+export const chip = createClassMapDirective({
+ getClasses: chipClasses,
+ setupElement: setupChip,
+});
diff --git a/labs/gb/components/chip/demo/demo.ts b/labs/gb/components/chip/demo/demo.ts
new file mode 100644
index 0000000000..b79d3ef4f8
--- /dev/null
+++ b/labs/gb/components/chip/demo/demo.ts
@@ -0,0 +1,63 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import './material-collection.js';
+import './index.js';
+
+import {
+ KnobTypesToKnobs,
+ MaterialCollection,
+ materialInitsToStoryInits,
+ setUpDemo,
+} from './material-collection.js';
+import {boolInput, Knob, selectDropdown} from './index.js';
+
+import {stories, StoryKnobs} from './stories.js';
+
+const collection = new MaterialCollection>(
+ 'Chip',
+ [
+ new Knob('color', {
+ ui: selectDropdown({
+ options: [
+ {value: 'elevated', label: 'Elevated'},
+ {value: 'filled', label: 'Filled'},
+ {value: 'tonal', label: 'Tonal'},
+ {value: 'outlined', label: 'Outlined'},
+ ],
+ }),
+ }),
+ new Knob('type', {
+ ui: selectDropdown({
+ options: [
+ {value: 'action', label: 'Action'},
+ {value: 'filter', label: 'Filter'},
+ {value: 'toggle', label: 'Toggle'},
+ ],
+ }),
+ }),
+ new Knob('selected', {
+ ui: boolInput(),
+ defaultValue: false,
+ }),
+ new Knob('removable', {
+ ui: boolInput(),
+ defaultValue: false,
+ }),
+ new Knob('disabled', {
+ ui: boolInput(),
+ defaultValue: false,
+ }),
+ new Knob('softDisabled', {
+ ui: boolInput(),
+ defaultValue: false,
+ }),
+ ],
+);
+
+collection.addStories(...materialInitsToStoryInits(stories));
+
+setUpDemo(collection, {fonts: 'roboto', icons: 'material-symbols'});
diff --git a/labs/gb/components/chip/demo/stories.ts b/labs/gb/components/chip/demo/stories.ts
new file mode 100644
index 0000000000..c51ada5988
--- /dev/null
+++ b/labs/gb/components/chip/demo/stories.ts
@@ -0,0 +1,164 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import '@material/web/labs/gb/components/chip/md-gb-chip.js';
+import '@material/web/labs/gb/styles/icon/md-gb-icon.js';
+
+import {MaterialStoryInit} from './material-collection.js';
+import {
+ type ChipColor,
+ type ChipType,
+} from '@material/web/labs/gb/components/chip/chip.js';
+import {adoptStyles} from '@material/web/labs/gb/styles/adopt-styles.js';
+import {styles as m3Styles} from '@material/web/labs/gb/styles/m3.cssresult.js';
+import {css, html} from 'lit';
+
+/** Knob types for chip stories. */
+export interface StoryKnobs {
+ color?: ChipColor;
+ type?: ChipType;
+ selected?: boolean;
+ removable?: boolean;
+ disabled?: boolean;
+ softDisabled?: boolean;
+}
+
+adoptStyles(document, [
+ m3Styles,
+ css`
+ :root {
+ --md-icon-font: 'Material Symbols Outlined';
+ }
+ `,
+]);
+
+const styles = css`
+ :host,
+ .demo-group {
+ font-family: var(
+ --md-sys-typescale-body-md-font,
+ var(--md-ref-typeface-plain, Roboto, sans-serif)
+ );
+ }
+ .demo-group {
+ display: flex;
+ gap: 12px;
+ flex-wrap: wrap;
+ align-items: center;
+ margin-bottom: 24px;
+ padding: 16px;
+ border: 1px solid var(--md-sys-color-outline-variant);
+ border-radius: 16px;
+ background-color: var(--md-sys-color-surface);
+ }
+ .chip-avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ background-color: var(--md-sys-color-primary);
+ color: var(--md-sys-color-on-primary);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 12px;
+ font-weight: 600;
+ }
+`;
+
+const playground: MaterialStoryInit = {
+ name: 'Playground',
+ styles,
+ render(knobs) {
+ return html`
+
+
+ star
+ Expressive Chip
+
+
+ `;
+ },
+};
+
+const variants: MaterialStoryInit = {
+ name: 'Expressive Action Variants',
+ styles,
+ render() {
+ return html`
+
+
+ schedule
+ Elevated Action
+
+
+ flight
+ Filled Action
+
+
+ event
+ Tonal Action
+
+
+ bookmark
+ Outlined Action
+
+
+ `;
+ },
+};
+
+const functional: MaterialStoryInit = {
+ name: 'Filter & Removable Chip',
+ styles,
+ render() {
+ return html`
+
+ Unselected Filter
+ Selected Filter
+ Removable Tag
+ Disabled Tag
+
+ `;
+ },
+};
+
+const avatarsAndIcons: MaterialStoryInit = {
+ name: 'Avatars & Leading Icons',
+ styles,
+ render() {
+ return html`
+
+
+ A
+ Avatar Chip
+
+
+ B
+ Removable Avatar
+
+
+ face
+ Leading Icon Chip
+
+
+ `;
+ },
+};
+
+/** Chip stories. */
+export const stories = [playground, variants, functional, avatarsAndIcons];
diff --git a/labs/gb/components/chip/md-gb-chip.ts b/labs/gb/components/chip/md-gb-chip.ts
new file mode 100644
index 0000000000..532702d90c
--- /dev/null
+++ b/labs/gb/components/chip/md-gb-chip.ts
@@ -0,0 +1,18 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {ChipElement} from './chip-element.js';
+
+export * from './chip-element.js';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ /** A Material Design Expressive Chip component. */
+ 'md-gb-chip': ChipElement;
+ }
+}
+
+customElements.define('md-gb-chip', ChipElement);