Skip to content

ActiveMultiSelect

Paulo Gomes da Cruz Junior edited this page Apr 13, 2026 · 1 revision

ActiveMultiSelect

The ActiveMultiSelect component is a custom multi-select input based on Carbon's FilterableMultiSelect. It supports a skeleton loading state, dynamic placeholder logic, and the underlying Carbon props, making it useful for controlled, filterable multi-select scenarios.

Key Features

  • Type Safety: Only accepts items with a code or value string property, so the component can derive a stable selected-value summary.
  • Dynamic Placeholder: When items are selected, the placeholder displays a comma-separated list of their code or value properties. If no items are selected, the original placeholder is shown.
  • External Control: The placeholder and selection state always reflect the latest selectedItems and placeholder props, even if changed externally by the parent.
  • Visual Feedback: When items are selected, the placeholder color is updated (via SASS) to match the primary text color, making it look like real text instead of a faded placeholder.
  • Focus Management: Fixes Carbon's persistent focus styling by removing outlines when the component should not have focus.
  • Deferred onChange: Wraps Carbon's onChange in queueMicrotask() to avoid React warnings about updating parent state during another component's render.
  • Skeleton State: Supports a skeleton loader for loading scenarios.

Props

Inherits Carbon's FilterableMultiSelect props, with the following addition and item constraint:

Name Type Required Description
showSkeleton boolean ❌ If true, renders a TextInputSkeleton with hideLabel instead of the multi-select.
items Array<{ code: string } | { value: string }> ✅ Items must expose either a code string or value string so the component can summarize selected values.

The component also defaults Carbon's selectionFeedback prop to top-after-reopen unless the parent overrides it.

Usage

import ActiveMultiSelect from "@/components/Form/ActiveMultiSelect";

<ActiveMultiSelect
  id="user-roles"
  items={roles} // roles: Array<{ code: string; name: string }>
  itemToString={(item) => item.name}
  showSkeleton={loading}
  onChange={handleChange}
  placeholder="Select roles..."
/>;

Placeholder Behavior

  • No selection: Shows the placeholder prop (e.g. "Select roles...").
  • With selection: Shows a comma-separated list of the selected items' code or value properties (e.g. "A, B").
  • External changes: If the parent clears or changes selectedItems (including to [], undefined, or null), the placeholder updates accordingly.

When an item contains both properties, code is used in preference to value.

Styling

  • When items are selected, the .cds--multi-select--selected class is added by Carbon. The component's SASS overrides the input's ::placeholder color to use the primary text color, making the placeholder look like real text.
  • Focus outlines are suppressed when the component is not focused, for a cleaner UI.

These styles are scoped under .active-multi-select-wrapper so they only affect this wrapper component.

Implementation Notes

  • The component renders inside an .active-multi-select-wrapper container so it can manage Carbon-specific focus and placeholder styling.
  • A document-level mousedown listener blurs the multi-select container and inner text input when the user clicks outside the component.
  • onChange is deferred with queueMicrotask() before calling the parent callback. This is intentional and prevents React warnings when the parent immediately updates controlled state.
  • When showSkeleton is enabled, the real multi-select is not rendered at all.

TypeScript Example

type MyItem = { code: string; label: string };

<ActiveMultiSelect<MyItem>
  items={myItems}
  selectedItems={selected}
  onChange={({ selectedItems }) => setSelected(selectedItems)}
  placeholder="Pick items..."
  itemToString={(item) => item.label}
/>;

Test Coverage

  • The component is tested for all placeholder scenarios, including user selection, external clearing, and edge cases (empty, undefined, or null selectedItems).
  • It is also tested for the skeleton state, item rendering, and support for both code-based and value-based item shapes.

Waste Plus Wiki

Home

Architecture

Codes

Decisions

Knowledge Base

Development

Changes

Clone this wiki locally