Skip to content

feat(F0Select): add group-header item #3591

Draft
miriam-mr90 wants to merge 8 commits intomainfrom
feat/f0-select-group-header-support
Draft

feat(F0Select): add group-header item #3591
miriam-mr90 wants to merge 8 commits intomainfrom
feat/f0-select-group-header-support

Conversation

@miriam-mr90
Copy link
Contributor

@miriam-mr90 miriam-mr90 commented Mar 4, 2026

Description

Add group-header as a new item type for the F0Select component when using static options. This allows consumers to visually separate options into labeled sections (e.g. "Assigned to me" / "All vacancies") without resorting to disabled items or manual separators.

A SelectSeparator is automatically rendered before each group header (except the first), so consumers only need to insert { type: "group-header", label: "..." } entries in their options array.

Fully backward compatible — existing item and separator types continue to work unchanged.

Screenshots

image

The dropdown shows two group headers ("Assigned to me" and "All vacancies") separating selectable options, with an automatic separator line between groups.

Implementation details

  • types.ts: Extended F0SelectItemProps union with a new { type: "group-header"; label: string } variant alongside the existing item and separator types.
  • F0Select.tsx (5 touch points):
    • defaultSearchFn — skips group-header items from search filtering (same as separator)
    • selectable callback — excludes group-header from selectable items
    • itemsByValue mapping — excludes group-header from the value map
    • onChange handler — excludes group-header from value extraction
    • getItems callback — renders a styled div matching the Figma "Dropdown header" spec (secondary text, font-medium, text-sm, padding 12/8/12px) with auto SelectSeparator before non-first group headers
  • F0Select.stories.tsx: Added a WithGroupHeaders story demonstrating group headers with static options. Updated the WithSearchBox story's custom searchFn to handle the new type.

Verification

Tests

  • Existing F0Select tests pass (12 passed, 1 skipped — pre-existing)
  • TypeScript compilation verified — no new type errors introduced
  • Lint passes with 0 warnings

Manual Verification

  • Verified in Storybook via the new WithGroupHeaders story
  • Group headers render with correct Figma styling (secondary color, font-weight 500, text-sm)
  • Headers are non-selectable and excluded from search/selection logic
  • Auto separator renders between groups but not before the first group

Copilot AI review requested due to automatic review settings March 4, 2026 16:41
@github-actions github-actions bot added feat react Changes affect packages/react labels Mar 4, 2026
@miriam-mr90 miriam-mr90 changed the title feat(F0Select): add group-header item type for static options feat(F0Select): add group-header item Mar 4, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

✅ No New Circular Dependencies

No new circular dependencies detected. Current count: 0

@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

📦 Alpha Package Version Published

Use pnpm i github:factorialco/f0#npm/alpha-pr-3591 to install the package

Use pnpm i github:factorialco/f0#db44f4b90daeed085aa9117e956aeebfeffa1e09 to install this specific commit

@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

🔍 Visual review for your branch is published 🔍

Here are the links to:

@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

Coverage Report for packages/react

Status Category Percentage Covered / Total
🔵 Lines 41.99% 8529 / 20311
🔵 Statements 41.34% 8754 / 21171
🔵 Functions 32.9% 1861 / 5655
🔵 Branches 31.73% 5073 / 15987
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/react/src/components/F0Select/F0Select.tsx 77.03% 57.14% 68.88% 77.29% 163, 170, 183-185, 197-199, 239, 263-266, 398-399, 405, 409-410, 430, 444, 462-463, 502, 515-548, 587, 599-603, 679-694, 700, 791, 809-846
packages/react/src/components/F0Select/types.ts 100% 100% 100% 100%
Generated in workflow #11492 for commit ae759de by the Vitest Coverage Report Action

@miriam-mr90
Copy link
Contributor Author

I promise that next time I’ll double-check all the proposed changes for a component beforehand and implement them all at once 🫠

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds group-header as a new item type to the F0Select component's static options API, allowing consumers to visually separate options into labeled sections. The feature is fully backward compatible — existing item and separator types are unchanged.

Changes:

  • Extended the F0SelectItemProps union type with { type: "group-header"; label: string }.
  • Updated F0Select.tsx at five touch points (search filtering, selectability, value mapping, onChange extraction, and getItems rendering) to handle the new type, with auto-separator insertion before non-first group headers.
  • Added a WithGroupHeaders Storybook story and updated WithSearchBox's searchFn to handle the new type.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
packages/react/src/components/F0Select/types.ts Adds { type: "group-header"; label: string } variant to the F0SelectItemProps union
packages/react/src/components/F0Select/F0Select.tsx Implements rendering and exclusion logic for the new group-header type at all relevant call sites
packages/react/src/components/F0Select/__stories__/F0Select.stories.tsx Adds WithGroupHeaders story and updates WithSearchBox custom searchFn


You can also share your feedback on Copilot code review. Take the survey.

When a consumer places a manual separator before a group-header, the
auto-separator logic would insert a second one. Now we check if the
previous rendered item is already a separator (height === 1) and skip
the auto-insertion in that case.
When search filtering removes all items under a group header, the
header would still be visible. Now a post-processing pass strips
group headers that have no selectable items between them and the
next header or end of list, along with their auto-separators.
…leanup

When search filtering removes all items, the splice operations in
the orphaned group header cleanup could leave the array shorter than
expected. Add a null check to prevent crash on undefined array access.
Cover group header rendering, accessibility (role=presentation),
non-selectability (clicking header doesn't trigger onChange),
orphaned header removal during search, and header restoration
when search is cleared.
Copilot AI review requested due to automatic review settings March 4, 2026 17:56
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +597 to +614
export const WithGroupHeaders: Story = {
args: {
label: "Select a vacancy",
placeholder: "Select a vacancy",
showSearchBox: true,
value: undefined,
options: [
{ type: "group-header", label: "Assigned to me" },
{ value: "vacancy-1", label: "Senior Frontend Engineer" },
{ value: "vacancy-2", label: "Product Designer" },
{ type: "group-header", label: "All vacancies" },
{ value: "vacancy-3", label: "Backend Engineer" },
{ value: "vacancy-4", label: "Data Analyst" },
{ value: "vacancy-5", label: "DevOps Engineer" },
{ value: "vacancy-6", label: "QA Engineer" },
],
},
}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Snapshot story is used for Chromatic visual regression testing, but the new WithGroupHeaders variant is not included in it. Per the F0 code review checklist (SKILL.md), all meaningful visual variants should be represented in the Snapshot story. Consider adding a group-headers variant to the Snapshot story so the group-header styling is captured in visual regression tests.

Copilot generated this review using guidance from repository custom instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat react Changes affect packages/react

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants