Chip

Material Design 3 chip component for tags, filters, selections, and user input

Chip

Chips help users enter information, make selections, filter content, or trigger actions. @duskmoon-dev/core provides a complete set of Material Design 3 chip variants including assist, filter, input, and suggestion chips.

Basic Usage

Basic Chip

Basic Chip

Chip Types

Material Design 3 defines four types of chips, each serving a specific purpose:

Assist Chips

Assist chips help users take contextual actions. They’re commonly used for smart or automated actions.

Assist Chips

Filter Chips

Filter chips allow users to refine content. They can be selected or unselected and often appear in groups.

Filter Chips

Input Chips

Input chips represent discrete pieces of information entered by a user, such as tags or contacts. They typically include a remove button.

Input Chips

JavaScript TypeScript React

Suggestion Chips

Suggestion chips help users explore related content or complete tasks. They’re similar to assist chips but focused on content discovery.

Suggestion Chips

Variants

Default Chips

Default chips with filled background:

Default Chips

Default Chip Primary Secondary Tertiary

Outlined Chips

Outlined chips with transparent background and border:

Outlined Chips

Outlined

Colors

Theme Colors

Theme Colors

Primary Secondary Tertiary

Semantic Colors

Use semantic colors to convey status or meaning:

Semantic Colors

Success Error Warning Info

Selected States

Filter chips support multiple selected state colors:

Selected States

With Icons

Add leading icons to provide visual context:

Chips with Icons

Tag Featured

With Avatar

Use avatars for chips representing people or user-generated content:

Chips with Avatar

User avatar John Doe User avatar Jane Smith

Sizes

Three sizes are available for different contexts:

Chip Sizes

Small Chip Default Chip Large Chip

Sizes work with all variants:

Chip Sizes with Variants

Small Avatar Large with Avatar

States

Disabled State

Disabled chips are non-interactive:

Disabled Chips

Disabled Chip

Interactive States

Chips can be clickable or selectable:

Interactive States

Chip Groups

Group related chips together with consistent spacing:

Chip Groups

React Vue Angular Svelte

Dense Chip Groups

Use dense spacing for compact layouts:

Dense Chip Groups

HTML CSS JavaScript TypeScript

Best Practices

Choosing the Right Chip Type

  1. Assist Chips: Use for smart suggestions and contextual actions (e.g., “Add to calendar”, “Set reminder”)
  2. Filter Chips: Use for filtering and refining content (e.g., category filters, search refinements)
  3. Input Chips: Use for user-entered discrete information (e.g., email recipients, tags)
  4. Suggestion Chips: Use for content discovery and exploration (e.g., “Trending”, “Popular”)

Best Practices - Clear Purpose

React TypeScript

Accessibility

  • Use <button> elements for clickable and selectable chips
  • Provide descriptive aria-label for remove buttons
  • Ensure sufficient color contrast
  • Support keyboard navigation (built-in for button elements)

Accessibility Examples

JavaScript

Label Length

Keep chip labels concise - typically 1-3 words:

Label Length Best Practices

JavaScript Web Development This is a very long label that wraps awkwardly

Visual Hierarchy

Use color and variant thoughtfully to create clear hierarchy:

Visual Hierarchy

Framework Examples

React

import { useState } from 'react';

interface ChipProps {
  children: React.ReactNode;
  variant?: 'default' | 'outlined';
  color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'error' | 'warning' | 'info';
  size?: 'sm' | 'md' | 'lg';
  selectable?: boolean;
  selected?: boolean;
  onRemove?: () => void;
  onClick?: () => void;
}

export function Chip({
  children,
  variant = 'default',
  color,
  size,
  selectable,
  selected,
  onRemove,
  onClick
}: ChipProps) {
  const classes = [
    'chip',
    variant === 'outlined' && 'chip-outlined',
    color && `chip-${color}`,
    size && `chip-${size}`,
    selectable && 'chip-selectable',
    selected && 'chip-selected',
    onClick && 'chip-clickable'
  ].filter(Boolean).join(' ');

  const Component = onClick || selectable ? 'button' : 'span';

  return (
    <Component className={classes} onClick={onClick}>
      {children}
      {onRemove && (
        <button className="chip-remove" onClick={onRemove} aria-label="Remove">
          <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
      )}
    </Component>
  );
}

// Usage: Filter chips
function FilterExample() {
  const [selected, setSelected] = useState('all');

  return (
    <div className="chip-group">
      <Chip selectable selected={selected === 'all'} onClick={() => setSelected('all')}>
        All
      </Chip>
      <Chip selectable selected={selected === 'active'} onClick={() => setSelected('active')}>
        Active
      </Chip>
      <Chip selectable selected={selected === 'completed'} onClick={() => setSelected('completed')}>
        Completed
      </Chip>
    </div>
  );
}

// Usage: Input chips with remove
function TagsExample() {
  const [tags, setTags] = useState(['React', 'TypeScript', 'Tailwind']);

  return (
    <div className="chip-group">
      {tags.map(tag => (
        <Chip key={tag} onRemove={() => setTags(tags.filter(t => t !== tag))}>
          {tag}
        </Chip>
      ))}
    </div>
  );
}

Vue

<template>
  <component
    :is="componentType"
    :class="chipClasses"
    @click="handleClick"
  >
    <slot />
    <button
      v-if="onRemove"
      class="chip-remove"
      @click="onRemove"
      aria-label="Remove"
    >
      <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
      </svg>
    </button>
  </component>
</template>

<script setup>
import { computed } from 'vue';

const props = defineProps({
  variant: {
    type: String,
    default: 'default'
  },
  color: String,
  size: String,
  selectable: Boolean,
  selected: Boolean,
  clickable: Boolean,
  onRemove: Function
});

const emit = defineEmits(['click']);

const componentType = computed(() => {
  return props.clickable || props.selectable ? 'button' : 'span';
});

const chipClasses = computed(() => {
  return [
    'chip',
    props.variant === 'outlined' && 'chip-outlined',
    props.color && `chip-${props.color}`,
    props.size && `chip-${props.size}`,
    props.selectable && 'chip-selectable',
    props.selected && 'chip-selected',
    props.clickable && 'chip-clickable'
  ].filter(Boolean).join(' ');
});

const handleClick = () => {
  if (props.clickable || props.selectable) {
    emit('click');
  }
};
</script>

<!-- Usage -->
<template>
  <div class="chip-group">
    <Chip
      v-for="category in categories"
      :key="category"
      selectable
      :selected="selectedCategory === category"
      @click="selectedCategory = category"
    >
      {{ category }}
    </Chip>
  </div>
</template>

API Reference

Class Names

ClassDescription
.chipBase chip styles (required)
.chip-outlinedOutlined variant with border
.chip-clickableClickable chip with hover states (assist/suggestion chips)
.chip-selectableSelectable chip with selection states (filter chips)
.chip-selectedSelected state (default/primary)
.chip-selected-primarySelected state with primary color
.chip-selected-secondarySelected state with secondary color
.chip-selected-tertiarySelected state with tertiary color
.chip-primaryPrimary color variant
.chip-secondarySecondary color variant
.chip-tertiaryTertiary color variant
.chip-successSuccess semantic color
.chip-errorError semantic color
.chip-warningWarning semantic color
.chip-infoInfo semantic color
.chip-smSmall size
.chip-lgLarge size
.chip-disabledDisabled state
.chip-iconLeading icon
.chip-avatarLeading avatar image
.chip-removeRemove/delete button
.chip-groupContainer for multiple chips
.chip-group-denseChip group with reduced spacing

HTML Elements

Use semantic HTML elements based on chip type:

  • Static chips: <span> element
  • Clickable chips (assist/suggestion): <button> element
  • Selectable chips (filter): <button> element with aria-pressed attribute
  • Input chips: <span> with <button> for remove action

Combinations

Common chip combinations:

Common Chip Combinations

User John Doe

See Also