Chips

Material Design 3 chip group with input, filter, and choice modes. Per-item color and variant overrides, 5 sizes, 4 style variants, overflow badge, and closable input chips. 82 controls, 13 properties. Supports up to 10 items.

cmpChips.yaml

Import via Components → New component → Import from code → paste YAML

Preview

Click × to remove chips

Installation

This component requires Modern controls to be enabled. Settings → Updates → Preview → Modern controls and themes

# In Power Apps Studio:
1. Components tab → New component → Import from code
2. Paste the full YAML definition
3. Add the component to any screen
4. Press F5 (Preview) to see the fully rendered component

Usage

This component is stateless

The chip component reads selected directly from the Items input and never toggles it internally. Your host app must manage state via a collection and update it through the OnSelect event. Without this wiring, filter and choice chips will not show checkmarks or selected fill states.

1. Define items in a collection

// Screen.OnVisible — first row must include all fields (schema row)
ClearCollect(colChips,
    { id: "1", label: "Approved", icon: "", color: "", variant: "", selected: false },
    { id: "2", label: "Rejected", color: "error" },
    { id: "3", label: "Pending", color: "warning" },
    { id: "4", label: "Draft" }
)

// Bind the component to the collection
cmpChips.Items = colChips

2. Filter chips — multi-select toggle

cmpChips.ChipType = "filter"

// OnSelect — toggle the clicked chip's selected state
UpdateIf(
    colChips,
    id = cmpChips.SelectedItem.id,
    { selected: !selected }
)

// Click "Approved" → selected flips to true
// → collection updates → component re-reads Items
// → chip shows checkmark + filled color

3. Choice chips — single select

cmpChips.ChipType = "choice"

// OnSelect — deselect all, then select the clicked chip
UpdateIf(colChips, true, { selected: false });
UpdateIf(
    colChips,
    id = cmpChips.SelectedItem.id,
    { selected: true }
)

4. Input chips — removable tags

cmpChips.ChipType = "input"
cmpChips.Config = { Closable: true }
cmpChips.Items = colChips

// OnClose — remove the chip from the collection
Remove(colChips,
    LookUp(colChips, id = cmpChips.SelectedItem.id))

// Add new tag from a TextInput
Collect(colChips,
    { id: Text(GUID()), label: txtTag.Text });
Reset(txtTag)

Properties

Input

PropertyTypeDefault
Items

Chip data: id, label, icon, color, variant, selected

Table10 sample chips
ChipType

"input" (removable), "filter" (multi-select), "choice" (single-select)

Text"input"
Color

Global fallback: "primary", "secondary", "success", "warning", "error"

Text"secondary"
Variant

Global fallback: "filled", "tonal", "outlined", "text"

Text"tonal"
Size

"x-small", "small", "default", "large", "x-large"

Text"default"
Config

Settings record: Theme, Wrap, Closable, Disabled, Radius, Gap, MaxVisible

RecordSee Config
CustomColors

Hex override per semantic color (primary, secondary, success, warning, error)

RecordAll empty ""
Icons

Prepend (global leading icon) and Check (filter checkmark character)

Record{Prepend:"", Check:"✓"}
CharWidths

Character width lookup table for pixel-perfect text measurement

TableSegoe UI Semibold

Output

PropertyTypeDescription
SelectedItemRecordFull record of the last clicked or closed chip (set via _chipSelected variable).

Events

EventDescription
OnSelectFires when a chip body is clicked. Hidden when input mode with Closable enabled to prevent accidental triggers.
OnCloseFires when the close (×) button is clicked. Only active when ChipType = "input" and Config.Closable = true.
OnOverflowFires when the overflow (+N) badge is clicked. Visible when Items count exceeds MaxVisible.

Implementation Details

Fixed 10-slot architecture

Like the breadcrumbs component, chips uses fixed slots (cntChip1cntChip10) instead of a gallery. Each slot contains 8 controls: outer container, content AutoLayout, icon image, auto-width label, close button group with image and button, plus a transparent hit-target button. Visibility is gated by CountRows(Items) >= N && N <= MaxVisible.

Color resolution cascade

Colors resolve in order: per-item color field → component-level Color property → CustomColors hex overrides → built-in Material palette. The same cascade applies for variant: per-item first, then the global Variant. This lets you mix tonal success chips with outlined primary chips in the same group.

Stateless selection by ChipType

The component never mutates its own Items — the host app owns all state. input: No selection state. Close button visible when Closable is true; the main hit button hides to prevent accidental taps. filter: Multi-select. Use UpdateIf(colChips, id = SelectedItem.id, { selected: !selected }) in OnSelect to toggle. A selected chip shows its filled color with a checkmark icon. choice: Single-select (radio). Use UpdateIf(colChips, true, { selected: false }) then UpdateIf(colChips, id = SelectedItem.id, { selected: true }) in OnSelect.

Pixel-perfect text width

Each chip label width is calculated using the CharWidths lookup table: Sum(Split(text,""), LookUp(CharWidths, Char=Value).Size) × FontSize × 1.05 + 6. This enables auto-width chips without a gallery, preventing text overflow and unnecessary whitespace.

Overflow badge

When MaxVisible is set and the Items table exceeds it, a btnOverflow button appears showing “+N”. Clicking it fires the OnOverflow event. The button displays a tooltip with the full count.

Icon support

Icons accept emoji (wrapped in SVG text element), raw SVG strings, or data: URIs. Set per-item via the icon field, or globally via Icons.Prepend. For filter chips, a selected chip with no custom icon shows the Icons.Check character (default “✓”).

Examples

Status tags (tonal, mixed colors)

ApprovedRejectedPendingDraft
// First row defines all columns (schema row)
cmpChips.Items = Table(
    { id:"1", label:"Approved",
      icon:"", color:"success",
      variant:"tonal", selected:false },
    { id:"2", label:"Rejected",
      color:"error" },
    { id:"3", label:"Pending",
      color:"warning" },
    { id:"4", label:"Draft" }
)
cmpChips.ChipType = "input"
cmpChips.Config = { Closable: false }

Size picker (choice, outlined)

SMLXL
// Screen.OnVisible
ClearCollect(colSizes, cmpChips.Items)

cmpChips.ChipType = "choice"
cmpChips.Variant = "outlined"
cmpChips.Items = colSizes

// OnSelect — single select
UpdateIf(colSizes, true,
    { selected: false });
UpdateIf(colSizes,
    id = cmpChips.SelectedItem.id,
    { selected: true })

Overflow with +N badge

Tag 1Tag 2Tag 3+7
// 10 items, only show 3
cmpChips.Config = {
    MaxVisible: 3,
    Gap: 8
}

// Handle overflow click
cmpChips.OnOverflow =
    Set(varShowAllTags, true)

Data Schema

Items record

Schema note: Power Apps infers table schema from the first row. The first item must include all optional fields (icon, color, variant, selected) to establish the schema. Subsequent rows can omit them — values fall back to component-level defaults via Coalesce.
FieldTypeNotes
idTextRequired. Unique identifier.
labelTextRequired. Display text. Width auto-calculated via CharWidths.
iconTextOptional. Emoji, SVG string, or data: URI. Falls back to Icons.Prepend.
colorTextOptional. "primary" / "secondary" / "success" / "warning" / "error". Falls back to component Color.
variantTextOptional. "filled" / "tonal" / "outlined" / "text". Falls back to component Variant.
selectedBooleanRequired for filter/choice. Component is stateless — manage via UpdateIf in OnSelect.

Config record

FieldTypeDefaultNotes
ThemeText"light""light" or "dark"
WrapBooleanfalseReserved. Chips scroll horizontally via LayoutOverflowX.
ClosableBooleantrueShow × button on input chips. Hides main OnSelect button.
DisabledBooleanfalseDisable close buttons and interactions.
RadiusNumber99Border radius in px. Clamped to half the chip height (pill by default).
GapNumber8Horizontal gap between chips (AutoLayout LayoutGap).
MaxVisibleNumber10Max chips shown before +N overflow badge appears.

Architecture

82 controls — 1 wrapper + 10 chip slots (8 controls each) + 1 overflow button.

13 properties — 9 input, 1 output, 3 events.

Default size — 800 × 50px. Height varies by Size property (38–62px).

cmpChips (width 800, height: x-small 38 / small 44 / default 50 / large 56 / x-large 62)
└── cntChipsWrapper (AutoLayout Horizontal, LayoutOverflowX: Scroll)
    ├── cntChip1 (visible: Items ≥ 1 && 1 ≤ MaxVisible)
    │   ├── cntContent1 (AutoLayout Horizontal, gap 4)
    │   │   ├── imgIcon1   — emoji/SVG/data: URI, or ✓ for selected filter
    │   │   ├── lblText1   — auto-width via CharWidths formula
    │   │   └── cntClose1  — visible: input + Closable + !Disabled
    │   │       ├── imgClose1 (× circle SVG, theme-aware)
    │   │       └── btnClose1 → Set(_chipSelected, ...); OnClose()
    │   └── btnChip1 → Set(_chipSelected, ...); OnSelect()
    │       (hidden when input + Closable to avoid double-tap)
    ├── cntChip2 … cntChip10  (identical pattern, Index offset)
    └── btnOverflow  → "+N" text, fires OnOverflow()
        (visible: Items > MaxVisible)