Chip
Chip represents a small, removable piece of information, such as a selected filter, an invited guest, or an uploaded file. Its label can be paired with an optional leading visual, such as an icon, an avatar photo, an image thumbnail, or a colored initials badge. It's always about one discrete, removable piece of data, so it ships with a working delete button by default.
Dependencies
When to use
Reach for a chip whenever the user is looking at a discrete, removable piece of data they added themselves, such as an applied filter, a recipient in a "to" field, or a file staged for upload. Each chip should read on its own, independent of the others around it. See Alternatives below if what you need instead is a static label with no removal behavior.
Install & usage
Pick a framework in the toolbar above and these snippets adapt.
npm install @eunomia/elements
import "@eunomia/elements/chip.js";
<eun-chip avatar-initials="AD">Alice Doe</eun-chip>
document.querySelector("eun-chip").addEventListener("eunclose", (event) => {
event.target.remove();
});
Importing the file registers <eun-chip> as a custom element, with no
further setup needed. It works with any framework, or none, since it's a
standard web component.
npm install @eunomia/elements
<script type="module">
import "@eunomia/elements/chip.js";
</script>
<eun-chip avatar-initials="AD">Alice Doe</eun-chip>
<script>
document.querySelector("eun-chip").addEventListener("eunclose", (event) => {
event.target.remove();
});
</script>
npm install @eunomia/elements
import "@eunomia/elements/chip.js";
function GuestChip() {
return (
<eun-chip
avatar-initials="AD"
oneunclose={(event) => event.target.remove()}
>
Alice Doe
</eun-chip>
);
}
npm install @eunomia/elements
"use client";
import "@eunomia/elements/chip.js";
export function GuestChip() {
return (
<eun-chip
avatar-initials="AD"
oneunclose={(event) => event.target.remove()}
>
Alice Doe
</eun-chip>
);
}
npm install @eunomia/elements
<script setup>
import "@eunomia/elements/chip.js";
</script>
<template>
<eun-chip avatar-initials="AD" @eunclose="(e) => e.target.remove()">
Alice Doe
</eun-chip>
</template>
npm install @eunomia/elements
import { CUSTOM_ELEMENTS_SCHEMA, Component } from "@angular/core";
import "@eunomia/elements/chip.js";
@Component({
selector: "app-guest-chip",
template: `
<eun-chip avatar-initials="AD" (eunclose)="onRemove($event)">
Alice Doe
</eun-chip>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class GuestChipComponent {
onRemove(event: Event) {
(event.target as HTMLElement).remove();
}
}
Alternatives
eun-tagGuidance
- Keep the label short and specific, such as a name, a filename, or a filter value, since it's the only reliably-perceived carrier of what the chip actually represents
- Pick one leading visual per chip:
avatarSrcfor a real photo,avatarInitialsfor a person with no photo,iconfor a category/type, or none at all for a plain label - Give
ariaLabelRemovea translated verb ("Retirer", "Entfernen"...) rather than leaving the English default in a localized UI. See the Accessibility tab - Move focus somewhere deliberate after removing a chip in response to
eunclose. See the Accessibility tab
- Using
eun-chipfor a static status or count that's never removed. See Alternatives above - Setting both
avatarSrc/avatarInitialsand expectingiconto still show. Only one leading visual ever renders, see the API tab for the precedence order - Relying on a generic, un-translated "Remove" across a whole list of chips in a non-English UI. See the Accessibility tab
- Overriding colors with inline styles instead of the
--chip-*CSS variables
Live testing
Properties
Chip <eun-chip>
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
| hide-icon | boolean | false | Whether the leading icon is hidden from the chip, once resolved. The avatar and initials are unaffected |
| avatar-src | string | — | The URL of a leading avatar or image. Takes priority over avatar initials and icon |
| avatar-alt | string | '' | The alt text for the avatar image. Left empty by default, since the slotted label already carries the identity. Set it only when the image conveys information the label doesn't |
| avatar-shape | 'circle' | 'square' | 'circle' | The shape of the leading avatar, initials, or image. Circle suits a person's photo, square a generic image thumbnail |
| avatar-initials | string | — | One or two characters shown in a colored badge in place of an image. Ignored once an avatar image is set, and takes priority over icon |
| aria-label-remove | string | Remove | A prefix combined with the chip's own slotted text to build the delete button's accessible name, such as "Remove Alice Doe", so multiple chips on the same page stay distinguishable to assistive technology. Defaults to the localized string for the current locale (English: "Remove") |
| color | 'primary' | 'secondary' | 'light' | 'medium' | 'dark' | 'medium' | The color to apply to the chip |
| severity | 'info' | 'success' | 'warning' | 'critical' | 'neutral' | — | The severity of the chip, matching the nature of the information conveyed. Takes priority over color when both are set |
| appearance | 'default' | 'fill' | 'outline' | 'flat' | 'default' | The surface style of the chip. Flat always renders the same muted, low emphasis surface regardless of color or severity |
| size | 's' | 'm' | 'l' | 'm' | The size of the chip |
| icon | EunomiaIconName | — | The leading icon to display. Ignored once an avatar image or initials are set. When severity is set and icon isn't, the icon is set according to the chip's severity |
| rounded | boolean | true | Whether the chip is fully rounded, as a pill |
| removable | boolean | true | Shows the delete button. Clicking it fires the close event without changing the chip's own rendering |
| disabled | boolean | false | Disables the delete button, preventing removal |
Import the exact TypeScript type behind any property above, see
Properties
JS-only — no matching HTML attribute, set these from a script or a template binding.
| Name | Type | Default | Description |
|---|---|---|---|
| locale | string | — | The locale used to resolve the default accessible label of the delete button. Defaults to the runtime's own |
| dictionary | — | This instance's locale-resolved string dictionary — see the class doc for the resolution order. |
Slots
| Name | Description |
|---|---|
| (default) | The chip's label |
| icon | Replaces the leading icon entirely with any content, not just an icon element. Falls back to the resolved icon or severity glyph when empty. Ignored once an avatar image or initials are set |
Events
| Name | Type | Description |
|---|---|---|
| eunclose | CloseEvent | Fired when the delete button is activated. The chip has no visibility state of its own, so removing or hiding it in response is the consumer's own responsibility |
Every event above follows the same naming convention, covered in
CSS custom properties
| Name | Description |
|---|---|
| --chip-background-color | Sets the background color of the chip |
| --chip-border-color | Sets the border color of the chip, for the outline appearance |
| --chip-border-width | Sets the border width of the chip, for the outline appearance |
| --chip-box-shadow | Sets a box shadow on the chip, none by default |
| --chip-color | Sets the text color of the chip |
| --chip-icon-color | Sets the color of the leading icon only, not the avatar, initials, or delete button icon. Defaults to matching the chip's own text color |
| --chip-border-radius | Sets the corner radius of the chip when rounded is unset |
| --chip-gap | Sets the gap between the chip's leading visual, label, and delete button |
| --chip-avatar-background | Sets the background color of the initials badge |
| --chip-avatar-color | Sets the text color of the initials badge |
| --chip-avatar-size | Sets the diameter of the leading avatar, initials, or image |
| --chip-delete-focus-outline-color | Sets the focus outline color of the delete button |
CSS shadow parts
| Name | Description |
|---|---|
| chip | The outer box wrapping the leading visual, label, and delete button. Exposed for effects the chip's CSS custom properties don't cover, such as an accent |
Label only
The minimal chip has no leading visual, just a slotted label and the default delete button. With nothing to fill the leading edge, the chip widens its own start padding a little so the label doesn't read as cramped against it. See "Icon and label" below for the other case that gets the same treatment, and "Avatar and label" for why an avatar/initials badge doesn't.
<eun-chip>Design</eun-chip>
Icon and label
A plain icon gets the same wider start padding as a label-only chip,
since it's small enough on its own that the default padding would
otherwise look uneven next to the label.
<eun-chip icon="star">Featured</eun-chip>
<eun-chip icon="folder" color="primary">Project files</eun-chip>
Need something other than a eun-icon, or a different icon library
entirely? Slot your own content into icon instead. It replaces the
prop-driven icon entirely (ignored, same as icon itself, once
avatarSrc/avatarInitials is set).
<eun-chip>
<svg
slot="icon"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="m12 2 2.9 6.9L22 10l-5.5 4.8L18 22l-6-3.7L6 22l1.5-7.2L2 10l7.1-1.1L12 2Z"
></path>
</svg>
Featured
</eun-chip>
Avatar and label
Set avatarSrc to a photo URL. It renders as a circle by default, inset
with the same padding as the label and delete button on every side
(unlike icon/label-only, an avatar already carries enough visual weight
against the edge on its own), e.g. a form's list of invited guests.
<eun-chip avatar-src="https://example.com/alice.jpg">Alice Doe</eun-chip>
<eun-chip avatar-src="https://example.com/bob.jpg">Bob Smith</eun-chip>
Image and label
Set avatarShape="square" alongside avatarSrc for a generic image
thumbnail instead of a person's photo, such as a file preview or a small
logo.
<eun-chip avatar-src="https://example.com/thumb.png" avatar-shape="square"
>report.pdf</eun-chip
>
Initials and label
Set avatarInitials for a person chip with no photo available: one or two
characters in a colored badge, matching color.
<eun-chip avatar-initials="AD">Alice Doe</eun-chip>
<eun-chip avatar-initials="BS" color="primary">Bob Smith</eun-chip>
Leading visual precedence
avatarSrc wins over avatarInitials, which wins over icon (itself
resolved from the explicit prop or, failing that, severity's own default
icon). Only one leading visual ever renders.
<eun-chip
avatar-src="https://example.com/alice.jpg"
avatar-initials="AD"
icon="star"
>All three set</eun-chip
>
Color
<eun-chip color="primary">Primary</eun-chip>
<eun-chip color="secondary">Secondary</eun-chip>
<eun-chip color="light">Light</eun-chip>
<eun-chip color="medium">Medium</eun-chip>
<eun-chip color="dark">Dark</eun-chip>
Part of the shared vocabulary covered in
Severity
Set severity for a state that maps to a semantic meaning
(info/success/warning/critical/neutral). Like eun-tag, it also picks a
matching default icon automatically, and takes precedence over color when
both are set.
<eun-chip severity="info">Info</eun-chip>
<eun-chip severity="success">Success</eun-chip>
<eun-chip severity="warning">Warning</eun-chip>
<eun-chip severity="critical">Critical</eun-chip>
<eun-chip severity="neutral">Neutral</eun-chip>
Unlike eun-tag, an explicit icon set alongside severity still wins over
the severity's own default icon. severity only drives the color here, so a
caller that needs its own icon per state (a status icon, for instance) keeps
full control of it.
<eun-chip severity="warning" icon="hourglass_empty">Pending</eun-chip>
<eun-chip severity="success" icon="check_circle">Confirmed</eun-chip>
Hiding the icon
Set hideIcon to drop the leading icon entirely, whether it came from an
explicit icon or a severity default. The avatar/initials leading visual
is unaffected, since hideIcon only ever governs the icon.
<eun-chip severity="critical" hide-icon>Overdue</eun-chip>
Display appearance
<eun-chip color="primary" appearance="default">Default</eun-chip>
<eun-chip color="primary" appearance="fill">Fill</eun-chip>
<eun-chip color="primary" appearance="outline">Outline</eun-chip>
<eun-chip color="primary" appearance="flat">Flat</eun-chip>
flat always renders the same muted, low-emphasis surface regardless of
color, matching eun-tag's own flat type.
Sizes
<eun-chip avatar-initials="AD" size="s">Small</eun-chip>
<eun-chip avatar-initials="AD">Medium</eun-chip>
<eun-chip avatar-initials="AD" size="l">Large</eun-chip>
Not rounded
Turn rounded off for a chip with a small corner radius (matching
eun-tag's own default shape) instead of a full pill.
<eun-chip avatar-initials="AD" id="square-chip">Alice Doe</eun-chip>
<script>
document.getElementById("square-chip").rounded = false;
</script>
rounded is a boolean property defaulting to true. Per web component
convention, writing the HTML attribute at all (even as rounded="false")
sets it to true, so turning it off means setting the JS property instead,
as above.
Not removable
Set removable to false for a chip that carries the same visual language
but isn't meant to be dismissed.
<eun-chip avatar-initials="AD" id="locked-chip">Alice Doe</eun-chip>
<script>
document.getElementById("locked-chip").removable = false;
</script>
Same boolean-attribute caveat as rounded above. removable defaults to
true, so opting out means setting the JS property, not writing
removable="false" in markup.
Disabled
Disables the delete button, preventing removal, and mutes the chip slightly.
<eun-chip avatar-initials="AD" disabled>Alice Doe</eun-chip>
Removing a chip
eun-chip dispatches eunclose and stops there. It never removes or hides
itself. The consumer decides what "removed" means, typically deleting the
element (or the underlying data item, in a framework-rendered list).
<div id="chip-list">
<eun-chip avatar-initials="AD">Alice Doe</eun-chip>
<eun-chip avatar-initials="BS">Bob Smith</eun-chip>
<eun-chip avatar-initials="CJ">Carla Jones</eun-chip>
</div>
<script>
document.getElementById("chip-list").addEventListener("eunclose", (event) => {
event.target.remove();
});
</script>
Custom colors
Override the --chip-* CSS variables, listed in full in the API tab.
Unlike eun-tag, these apply regardless of which color is set, since
every color branch itself reads through the corresponding --chip-*
variable.
<eun-chip class="custom-chip" avatar-initials="ZK">Custom</eun-chip>
<eun-chip appearance="outline" icon="warning" class="custom-icon-chip"
>Pending review</eun-chip
>
.custom-chip {
--chip-background-color: #fdf2f8;
--chip-color: #be185d;
--chip-avatar-background: #be185d;
--chip-border-width: 2px;
--chip-border-color: #be185d;
--chip-box-shadow: 0 2px 8px rgba(190, 24, 93, 0.25);
}
.custom-icon-chip {
--chip-icon-color: #c85207;
}
Keyboard interactions
| Key | Action |
|---|---|
Tab / Shift+Tab |
Moves focus to/from the delete button, when removable is set |
Space / Enter |
Activates the focused delete button, native <button> behavior |
eun-chip itself is never focusable and carries no tabindex. It isn't a
single interactive control, it's a label with an interactive delete affordance
inside it. When removable is unset there is nothing in it to reach with
the keyboard at all. It reads exactly like a eun-tag would.
Delete button semantics
The delete button is a real eun-button (ghost rounded size="xs", an
icon-only eun-icon child), so it inherits a native, fully accessible
<button> under the hood with no extra work here. See
ariaLabelRemove (default "Remove") combined with the chip's own slotted
text (e.g. "Remove Alice Doe"), computed automatically off the default
slot's content. This matters more here than it does for
ariaLabelRemove ("Retirer", "Entfernen"...) for a localized UI.
Leaving the English default in place while the label text itself is
localized produces a mixed-language accessible name.
Leading visual is decorative
The leading icon renders via eun-icon, which always sets
aria-hidden="true" on itself (see its own Accessibility tab). The initials
badge (avatarInitials) is likewise aria-hidden="true" on the chip's own
markup. Neither is ever announced, and neither is a substitute for the
label text. The identity or category they represent should already be
spelled out in the slotted label itself (a chip reading "Alice Doe" next to
her initials, not initials alone).
Avatar image alt text
The avatarSrc image defaults to alt="" (decorative) for the same reason:
the slotted label already names who or what the avatar represents, so a
redundant alt text would just have a screen reader announce the same name
twice in a row. Set avatarAlt explicitly only when the image conveys
something the label text genuinely doesn't, such as a photo used as the
sole identifier with no accompanying name, per
Focus management on removal is your responsibility
eun-chip dispatches eunclose and stops there. It never removes or hides
itself (see "Removing a chip" in the Examples tab). If your eunclose
handler removes the element from the DOM while focus was still on its
delete button, the browser drops focus to <body>, and a keyboard user
loses their place per
Don't rely on color alone
color changes the chip's visual appearance only.
Color contrast
The default and fill types are built from this design system's own color
tokens, already chosen to meet contrast minimums against their paired
background. A custom --chip-background-color/--chip-color combination
(or a custom brand color) must still be checked against
--_backgroundFilled color specifically so it stays legible
regardless of the active appearance. A custom --chip-avatar-background /
--chip-avatar-color pair needs the same contrast check independently, since
it's a separate foreground/background pair from the label text.
Reference links