Skip to content

HyChip ​

Usage examples on this page are written for Lit / plain HTML (<hy-chip>). The same component ships as HyChip in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

A compact, interactive element for displaying tags, filters, selections, or actions.

Chips are versatile UI elements that can represent inputs, attributes, or actions. Unlike badges (which are non-interactive status indicators), chips support user interaction including clicking, selecting, and removing.

Key Features ​

  • Multiple semantic variants (neutral, brand, success, warning, danger, info), and highlight for the one chip that stands out on a screen
  • Optional remove button for dismissible chips
  • Action chips (interactive: a click fires activate, nothing toggles) and filter chips (interactive selectable: a click toggles selected)
  • Link mode when href is provided
  • Icon and avatar support via prefix/suffix slots
  • Full keyboard navigation (Enter, Space, Backspace, Delete)
  • SSR compatible

Accessibility: built in ​

  • Proper ARIA roles and states
  • Keyboard navigation with focus indicators
  • Screen reader announcements
  • High contrast mode support
  • Reduced motion support
  • Named from the host: aria-label / aria-labelledby on <hy-chip> name the chip (resolved to text, since an IDREF can't cross the shadow boundary)

Accessibility: your part ​

  • After you remove a chip on remove, move focus to the next chip, or to the field when none is left.
  • Wrap a set of filter chips in an element with role="group" and an aria-label, or put them under a visible heading.

Icon-only chip ​

A chip with a glyph (icon, the prefix or suffix slot) and nothing in its default slot is square at every size and density: the empty label makes no box, and the chip's width equals its height. Name it on the host with aria-label — an interactive icon-only chip without one dev-warns. A removable chip keeps its padding (the remove button needs the room). The server render keeps the label part; the first client update drops it.

When to use

  • A filter people turn on and off, with selectable.
  • A value people remove: an applied filter, a selected tag, with removable.
  • A tag on a thing that people can act on.

Do

  • Keep it to a word or two.
  • Keep the chips of a row the same kind: all filters or all tags.

When not to use

  • A label nothing happens on when clicked: hy-badge.
  • The main action of a screen or form: hy-button.
  • One setting chosen from several, kept on screen: hy-toggle-group, hy-radio-group or hy-select.
  • Tokens people type into a field, such as recipients or tags: hy-multi-combobox.

Examples ​

Basic Chip ​

html
<hy-chip>Label</hy-chip>

With Icon ​

html
<hy-chip icon="heart">Favorites</hy-chip>

Removable Chip ​

html
<hy-chip removable>Removable</hy-chip>

Filter chip (selectable) ​

html
<!-- A click toggles `selected` and fires `select`; announced as a toggle button. -->
<hy-chip selectable>Unread</hy-chip>
<hy-chip selectable selected>Starred</hy-chip>

Action chip ​

html
<!-- A button that looks like a chip: fires `activate`, never changes its own state. -->
<hy-chip icon="filter">Filters</hy-chip>

Icon-only chip ​

html
<!-- Square, named on the host. -->
<hy-chip icon="list-check" variant="success" aria-label="No accessibility issues"></hy-chip>
html
<hy-chip href="/category/design">Design</hy-chip>

Variants ​

html
<hy-chip variant="neutral">Neutral</hy-chip>
<hy-chip variant="brand">Brand</hy-chip>
<hy-chip variant="success">Success</hy-chip>
<hy-chip variant="warning">Warning</hy-chip>
<hy-chip variant="danger">Danger</hy-chip>

Categorical / Identity tag ​

html
<!-- Hash an identity string to a stable slot in a named group. -->
<hy-chip category-group="team" identity="user-alice">Alice</hy-chip>
<!-- Explicit slot beats identity. -->
<hy-chip category-group="team" slot-index="3">Frontend</hy-chip>
<!-- A non-neutral variant wins — categorical is ignored. -->
<hy-chip variant="brand" category-group="team" slot-index="3">Brand (categorical skipped)</hy-chip>

Event Handling ​

javascript
const chip = document.querySelector('hy-chip[removable]');

chip.addEventListener('remove', (event) => {
  console.log('Chip removed:', event.detail.chip);
  event.detail.chip.remove(); // Remove from DOM
});

chip.addEventListener('select', (event) => {
  console.log('Selection changed:', event.detail.selected);
});

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
variantvariant'neutral' | 'brand' | 'success' | 'warning' | 'danger' | 'info' | 'highlight''neutral'Visual style variant determining the chip's color scheme and semantic meaning.
emphasisemphasis'solid' | 'soft' | 'outlined' | 'tinted''soft'Visual chrome weight on top of the role.
sizesize'small' | 'medium' | 'large''medium'Physical size of the chip affecting dimensions, padding, and typography.
interactiveinteractivebooleantrueWhether the chip is interactive (clickable, focusable, and responds to keyboard). An interactive chip is a button: a click fires activate and changes nothing on the chip — add selectable for a filter chip that toggles. When false, the chip renders as a static display element without button semantics, making it suitable for tags or labels that don't require user interaction.
selectableselectablebooleanfalseMakes an interactive chip a filter chip: a click (or Enter / Space) toggles selected and fires select, and the chip is announced as a toggle button (aria-pressed). Without it a click only fires activate — right for a chip that opens a menu or runs an action, which must not change its look when clicked. No effect on a link chip or a non-interactive one.
removableremovablebooleanfalseShows a remove button that allows the user to dismiss the chip. When clicked, fires the remove event. The chip can also be removed by pressing Backspace or Delete when focused.
disableddisabledbooleanfalseDisables the chip, preventing interaction and applying disabled styling. Disabled chips cannot be clicked, selected, or removed.
selectedselectedbooleanfalseIndicates whether the chip is in a selected state, and paints it with the role's on token. Useful for filter chips, toggle chips, or multi-select scenarios. A click toggles it only on a selectable chip (and fires select); on any other chip it is the app's to set.
hrefhrefstring | undefined—When set, renders the chip as an <a> tag with this href. The chip will navigate to the specified URL when clicked.
targettarget'_blank' | '_parent' | '_self' | '_top'—Specifies where to open the linked document. Only used when href is set. When set to _blank, automatically adds rel="noreferrer noopener" for security.
removeLabelremove-labelstring'Remove {label}'Accessible label for the remove button, a template: {label} is replaced by the chip's text (Remove {label} reads "Remove JavaScript"); with no text the label is the template's own words, trimmed. A label without {label} is used as written. Use for internationalization.
iconiconstring | undefined—Name of the icon to display before the label. When set, renders an hy-icon in the shadow DOM instead of using the prefix slot.
categoryGroupcategory-groupstring | undefined—Categorical group name to hash into. Only applied when variant is neutral; a non-neutral variant wins. Selects which palette in the active DS's roles.categorical map this chip pulls from.
identityidentitystring | undefined—Identity string hashed to a stable slot within categoryGroup — same identity always produces the same color. Ignored when slotIndex is set.
slotIndexslot-indexnumber | undefined—Explicit 1-indexed slot within categoryGroup. Takes precedence over identity. Out-of-range values fall back to default styling.

Events ​

EventDetailDescription
activate—Fired when chip is clicked. Detail: { originalEvent: MouseEvent | KeyboardEvent }
remove—Fired when remove button is clicked or Backspace/Delete pressed. Detail: { chip: HyChip, originalEvent: MouseEvent | KeyboardEvent }
select—Fired when a selectable chip's selection state changes (never on a chip without selectable). Detail: { selected: boolean, originalEvent: MouseEvent | KeyboardEvent }

Slots ​

SlotDescription
defaultThe chip's label text
prefixContent before the label (icon, avatar)
suffixContent after the label, before remove button (icon, count)

CSS Parts ​

PartDescription
baseThe chip's base wrapper element
labelThe default slot containing chip text
remove-buttonThe remove button element (when removable)

CSS Custom Properties ​

The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.

PropertyDefaultDescription
--hy-chip-background-brand-soft-restvar(--hy-background-brand-soft-rest)One of the generated color hooks (paint/chip.mjs): --hy-chip[-<part>]-<family>-<variant>-<emphasis-or-on>-<state> (family: background, foreground or border), one per cell and state, each falling back to the job token of the same name (the default cell is neutral soft). Components ▸ Add an override lists them all.
--hy-chip-gap-pill-md-inlinevar(--hy-gap-pill-md-inline)Gap between elements
--hy-chip-gap-pill-sm-inlinevar(--hy-gap-pill-sm-inline)Gap between elements
--hy-chip-gap-pill-lg-inlinevar(--hy-gap-pill-lg-inline)Gap between elements
--hy-chip-control-height-xsvar(--hy-control-height-xs)Height at small size
--hy-chip-control-height-smvar(--hy-control-height-sm)Height at medium size
--hy-chip-control-height-mdvar(--hy-control-height-md)Height at large size
--hy-chip-padding-pill-sm-inlinevar(--hy-padding-pill-sm-inline)Horizontal padding at small size
--hy-chip-padding-pill-md-inlinevar(--hy-padding-pill-md-inline)Horizontal padding at medium size
--hy-chip-padding-pill-lg-inlinevar(--hy-padding-pill-lg-inline)Horizontal padding at large size
--hy-chip-radius-pill-mdvar(--hy-radius-pill-md)Border radius
--hy-chip-stroke-smvar(--hy-stroke-sm)Border width
--hy-chip-text-transformnoneText transform for chip label
--hy-chip-body-md-font-familyvar(--hy-body-md-font-family)Font family override for chip label
--hy-chip-body-sm-font-familyvar(--hy-body-sm-font-family)Font family override for chip label
--hy-chip-body-lg-font-familyvar(--hy-body-lg-font-family)Font family override for chip label
--hy-chip-motion-transition-hover-durationvar(--hy-motion-transition-hover-duration)Transition duration for hover and focus state feedback
--hy-chip-motion-transition-hover-easingvar(--hy-motion-transition-hover-easing)Transition easing for hover and focus state feedback

Methods ​

focus() ​

Sets focus on the chip.

blur() ​

Removes focus from the chip.

Built with Lit. Documented with VitePress.