Skip to content

cv-chip

Compact interactive token for filters, applied facets, tags, and secondary action clusters.

Use cv-chip when the visible token does something: activates a filter editor, toggles a value through cv-chip-group, or exposes a dedicated remove action.

Usage

View source
html
<div class="chip-demo-shell" data-demo="chip">
  <section class="chip-demo-hero" aria-labelledby="chip-demo-title">
    <div class="chip-demo-copy">
      <span class="chip-demo-kicker">Interactive token</span>
      <h3 id="chip-demo-title">Use chips when the label is also a control.</h3>
      <p>
        A chip carries a stable value, optional selected state, and optional remove action in the same compact
        surface.
      </p>
    </div>

    <div class="chip-demo-rack" aria-label="Chip behavior examples">
      <div class="chip-demo-cell chip-demo-cell--good">
        <span class="chip-demo-label">Applied filter</span>
        <cv-chip value="local" selected removable>
          <span slot="prefix">#</span>
          Local vault
        </cv-chip>
        <p>Selected token with a remove affordance.</p>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Quick action</span>
        <cv-chip value="filter-rule">
          <span slot="prefix">+</span>
          Add rule
        </cv-chip>
        <p>Clickable token that can open a focused editor.</p>
      </div>
    </div>
  </section>

  <section class="chip-demo-section" aria-labelledby="chip-demo-states-title">
    <div class="chip-demo-section-header">
      <span class="chip-demo-kicker">States</span>
      <h4 id="chip-demo-states-title">Action, selected, removable, disabled, and size variants</h4>
    </div>

    <div class="chip-demo-state-grid">
      <div class="chip-demo-cell">
        <span class="chip-demo-label">Action</span>
        <cv-chip value="edit-filter">Open filter</cv-chip>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Selected</span>
        <cv-chip value="work" selected>Work</cv-chip>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Removable</span>
        <cv-chip value="otp" removable>OTP seeds</cv-chip>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Disabled</span>
        <cv-chip value="remote" disabled>Remote sync</cv-chip>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Small</span>
        <cv-chip value="small" size="small">Compact</cv-chip>
      </div>

      <div class="chip-demo-cell">
        <span class="chip-demo-label">Large pill</span>
        <cv-chip value="large" size="large" pill selected>Threat model</cv-chip>
      </div>
    </div>
  </section>

  <section class="chip-demo-section" aria-labelledby="chip-demo-events-title">
    <div class="chip-demo-section-header">
      <span class="chip-demo-kicker">Event contract</span>
      <h4 id="chip-demo-events-title">Activation and removal emit different events</h4>
    </div>

    <div class="chip-demo-event-panel">
      <div class="chip-demo-event-row" aria-label="Interactive chip event examples">
        <cv-chip value="files" removable selected>Files</cv-chip>
        <cv-chip value="notes">Notes</cv-chip>
        <cv-chip value="media" removable>Media</cv-chip>
      </div>
      <output class="chip-demo-output" aria-live="polite">Event log appears here.</output>
    </div>
  </section>
</div>

<script>
  document.querySelectorAll('.chip-demo-shell[data-demo="chip"]:not([data-ready])').forEach((shell) => {
    shell.dataset.ready = 'true'
    const output = shell.querySelector('.chip-demo-output')
    shell.addEventListener('cv-chip-action', (event) => {
      output.textContent = `cv-chip-action: ${event.detail.value} via ${event.detail.source}`
    })
    shell.addEventListener('cv-chip-remove', (event) => {
      output.textContent = `cv-chip-remove: ${event.detail.value}`
    })
  })
</script>

Anatomy

<cv-chip> (host)
└── <span part="base" role="button">
    ├── <span part="prefix">
    ├── <span part="label">
    ├── <span part="suffix">
    └── <button part="remove-button"> optional

Attributes

AttributeTypeDefaultDescription
valueString""Value used by chip-group selection
selectedBooleanfalseSelected state
disabledBooleanfalseBlocks chip action and remove events
removableBooleanfalseShows remove button
variantString"neutral"Visual variant
sizeString"medium""small", "medium", or "large"
pillBooleanfalseFully rounded chip shape

Slots

SlotDescription
(default)Chip label
prefixLeading content
suffixTrailing content

CSS Parts

PartDescription
baseAction surface
prefixPrefix slot wrapper
labelDefault slot wrapper
suffixSuffix slot wrapper
remove-buttonRemove action button

Events

EventDetailDescription
cv-chip-action{ value: string, source: "click" | "keyboard" }Emitted by a chip activation
cv-chip-remove{ value: string }Emitted by a chip remove button

Keyboard

KeyBehavior
Enter/SpaceActivates the focused chip

Arrow-key roving focus is handled by cv-chip-group, not by a standalone chip.

When to use chip vs badge

NeedUse
Applied filter, selected tag, quick facet, removable tagcv-chip
Passive state, count, warning label, status dotcv-badge
Single or multiple selection across several chipscv-chip-group

Behavior notes

  • selected changes the pressed state and maps to aria-pressed.
  • disabled removes the chip from tab order and blocks action/remove events.
  • removable adds a nested remove button that emits cv-chip-remove without also emitting cv-chip-action.
  • value is the stable payload consumed by events and by cv-chip-group.

ChromVoid UIKit documentation