You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add multi-select, searchable, grouped checkbox-filter capabilities to the Dropdown paragon component #256
In frontend-app-admin-console we built a MultipleChoiceFilter component on top of Paragon's Dropdown + Form.CheckboxSet to power the table filters in the authz module. It's a reusable "dropdown of checkboxes" filter: multi-select, optionally searchable, optionally grouped, with a toggle that reflects how many items are selected.
Rather than keep this living in a single frontend app, we'd like to upstream its behavior into Paragon so every Open edX frontend can use it. After discussing with the Paragon maintainers (Brian Smith), the agreed direction is not a brand-new component but to fold these capabilities into the existing Dropdown component (and its menu primitives) so it natively supports a multi-select / searchable filter pattern. This is effectively the long-requested "multi-select for Dropdown" that has come up repeatedly since ~2022 (e.g. the "assign taxonomies to organizations" use case).
Agreed direction
Extend Dropdown, don't add a new component. Keep the React-Bootstrap custom dropdown under the hood (Paragon still uses it), but expose multi-select and search natively so consumers no longer have to hand-build a custom menu (Dropdown.Menu as custom menu, inline Form.Control to type-filter, etc.). The goal is for Paragon props to cover what today requires a bespoke menu.
This is the recurring multi-select ask. The filter component is essentially the multi-select-in-a-dropdown pattern people have wanted for years; a filter is a prime use case for it.
Must be data-source agnostic. Paragon can have components tied to data sources, but the data wiring must not be part of the component — it has to be standalone enough that the doc-site examples make sense by just passing data in.
Accessibility review is the main gate. A button that opens a menu allowing multiple selections has known a11y complexity: keyboard navigation, screen-reader support, knowing what is/isn't selected, and how to exit the menu. These concerns have blocked similar proposals before. Plan: have an accessibility team run testing against the preview doc site (so they don't need to pull code) and document the results on the PR.
Process: no formal component-proposal template is required here because working code already exists. Open a PR with strong doc-site examples, reach out to the Paragon Working Group (how to contribute), and add it to the working-group agenda for a synchronous review.
Figma is not required up front. Since this is an existing, working component (not a brand-new proposal), code lands first and is the source of truth. Once approved, someone on the design side adds it to Figma so designers know it's available.
Motivation
The pattern (a dropdown toggle that opens a scrollable list of checkboxes used as a filter) is common across apps, and each one currently hand-rolls it. It's already used in more than one place (admin console + Studio-style dashboards), which is a good reason to centralize it.
Our implementation leans on Paragon internals (Dropdown, Form.CheckboxSet, Form.Checkbox, Form.Control, Icon, Stack) plus custom CSS classes (no-caret-dropdown, filters, pgn__dropdown-filter-checkbox-group, pgn__dropdown-filter-group-name) that would be better expressed as first-class Paragon styles/tokens.
Centralizing it gives accessibility, theming (design tokens), and i18n consistency for free, and removes per-app drift. It saves real code on every app that needs filtering.
Current behavior (what we want Paragon to support)
Multi-select checkboxes — menu renders a Form.CheckboxSet; selecting toggles values in/out of an array. Parent is notified via a setFilter(values, changedItem) style callback.
Selection-aware toggle — the toggle switches variant (outline-primary → primary) when anything is selected and appends the selected count, e.g. Organizations (3). Supports a leading icon (iconSrc) and a trailing filter icon, with the default caret suppressed.
Optional search (isSearchable) — renders a Form.Control search box at the top of the menu with an onSearchChange callback (supports server-side/async filtering, as OrgFilter does), plus a "more results" hint row.
Optional grouping (isGrouped) — choices carry a groupName (+ optional groupIcon); the menu renders grouped sections with a group header.
Rich option rows — each choice can show a displayName and an optional secondary description line.
"Showing X of Y" count — a small count line at the top of the list.
Disabled / limit state (disabled) — new selections can be disabled (used to enforce a max-applied-filters limit) while already-checked items remain toggle-off-able.
Proposed approach
Extend Dropdown so multi-select/search is a built-in capability rather than a custom menu. Open questions for the maintainers (to confirm on the PR):
API surface: a dedicated subcomponent (e.g. Dropdown.Filter / Dropdown.CheckboxMenu) vs. new props on Dropdown.Menu + a Dropdown.CheckboxItem? Keep it composable with the existing Dropdown API and the React-Bootstrap dropdown underneath.
State model: controlled selectedValues + onChange(values, changedItem) as the canonical contract; keep an uncontrolled variant?
Search: built-in client-side filtering with an escape hatch (onSearchChange) for async/server-side filtering. Keep the data source outside the component.
Grouping: accept flat items with a group field (current approach) or nested group objects?
Styling/tokens: promote the custom classes to Paragon styles backed by design tokens; suppress-caret should be a supported prop/variant, not a custom class.
Virtualization/limits: relevant to paragon#3133 (max items in menu) — worth coordinating.
Acceptance criteria
Dropdown supports a multi-select checkbox menu as a first-class, documented pattern (no custom menu required by consumers).
Component is data-source agnostic; data is passed in and doc-site examples stand alone.
Supports optional search (client-side built in; async via callback).
Supports optional grouped sections with group headers/icons.
Supports per-option secondary description text.
Toggle reflects selection state (variant change + count) with optional leading icon and no forced caret.
Supports disabling new selections while keeping existing selections removable.
Accessibility review completed by an internal a11y team against the preview doc site, with results documented on the PR: keyboard navigation, screen-reader labeling, clear selected/unselected state, and a clear way to exit the menu.
Themed via design tokens (no hardcoded colors/magic numbers); no app-specific CSS classes required.
i18n: all built-in strings (search placeholder, "showing X of Y", "more results") are localizable.
Documented in the Paragon site with examples (basic multi-select, searchable, grouped).
Target repo:
openedx/paragonType: Feature / Enhancement
Origin:
openedx/frontend-app-admin-console—src/authz-module/components/TableControlBar/MultipleChoiceFilter.tsxSummary
In
frontend-app-admin-consolewe built aMultipleChoiceFiltercomponent on top of Paragon'sDropdown+Form.CheckboxSetto power the table filters in the authz module. It's a reusable "dropdown of checkboxes" filter: multi-select, optionally searchable, optionally grouped, with a toggle that reflects how many items are selected.Rather than keep this living in a single frontend app, we'd like to upstream its behavior into Paragon so every Open edX frontend can use it. After discussing with the Paragon maintainers (Brian Smith), the agreed direction is not a brand-new component but to fold these capabilities into the existing
Dropdowncomponent (and its menu primitives) so it natively supports a multi-select / searchable filter pattern. This is effectively the long-requested "multi-select for Dropdown" that has come up repeatedly since ~2022 (e.g. the "assign taxonomies to organizations" use case).Agreed direction
Dropdown, don't add a new component. Keep the React-Bootstrap custom dropdown under the hood (Paragon still uses it), but expose multi-select and search natively so consumers no longer have to hand-build a custom menu (Dropdown.Menu ascustom menu, inlineForm.Controlto type-filter, etc.). The goal is for Paragon props to cover what today requires a bespoke menu.Motivation
Dropdown,Form.CheckboxSet,Form.Checkbox,Form.Control,Icon,Stack) plus custom CSS classes (no-caret-dropdown,filters,pgn__dropdown-filter-checkbox-group,pgn__dropdown-filter-group-name) that would be better expressed as first-class Paragon styles/tokens.Current behavior (what we want Paragon to support)
Reference implementation:
MultipleChoiceFilter.tsx. Features:Form.CheckboxSet; selecting toggles values in/out of an array. Parent is notified via asetFilter(values, changedItem)style callback.variant(outline-primary→primary) when anything is selected and appends the selected count, e.g.Organizations (3). Supports a leading icon (iconSrc) and a trailing filter icon, with the default caret suppressed.isSearchable) — renders aForm.Controlsearch box at the top of the menu with anonSearchChangecallback (supports server-side/async filtering, asOrgFilterdoes), plus a "more results" hint row.isGrouped) — choices carry agroupName(+ optionalgroupIcon); the menu renders grouped sections with a group header.displayNameand an optional secondarydescriptionline.disabled) — new selections can be disabled (used to enforce a max-applied-filters limit) while already-checked items remain toggle-off-able.Proposed approach
Extend
Dropdownso multi-select/search is a built-in capability rather than a custom menu. Open questions for the maintainers (to confirm on the PR):Dropdown.Filter/Dropdown.CheckboxMenu) vs. new props onDropdown.Menu+ aDropdown.CheckboxItem? Keep it composable with the existingDropdownAPI and the React-Bootstrap dropdown underneath.selectedValues+onChange(values, changedItem)as the canonical contract; keep an uncontrolled variant?onSearchChange) for async/server-side filtering. Keep the data source outside the component.groupfield (current approach) or nested group objects?Acceptance criteria
Dropdownsupports a multi-select checkbox menu as a first-class, documented pattern (no custom menu required by consumers).frontend-app-admin-consoleto drop its localMultipleChoiceFilterin favor of the Paragon API.Contribution plan
openedx/paragonextendingDropdown, with doc-site examples (basic multi-select, searchable, grouped).frontend-app-admin-consoleto replace the local component.References
MultipleChoiceFilter.tsxDropdown/ React-Bootstrap custom dropdown docs: https://paragon-openedx.netlify.app/components/dropdown/