Skip to content

feat(Toolbar,OverflowMenu): support responsive height vis breakpoints#12347

Draft
kmcfaul wants to merge 1 commit intopatternfly:mainfrom
kmcfaul:responsive-heights
Draft

feat(Toolbar,OverflowMenu): support responsive height vis breakpoints#12347
kmcfaul wants to merge 1 commit intopatternfly:mainfrom
kmcfaul:responsive-heights

Conversation

@kmcfaul
Copy link
Copy Markdown
Contributor

@kmcfaul kmcfaul commented Apr 10, 2026

What: Closes #12335

Needs patternfly/patternfly#8295 to be pulled in when merged for styling

  • Adds visibilityAtHeight props to ToolbarItem, ToolbarGroup, ToolbarContent that allows visibility to be changed based on specific height breakpoints
  • Adds isVertical to OverflowMenu that changes the layout orientation for vertical toolbars/elements that use OverflowMenu
  • Adds examples for Toolbar and OverflowMenu

Summary by CodeRabbit

  • New Features

    • Added vertical orientation support to OverflowMenu component
    • Added height-based responsive behavior for OverflowMenu and Toolbar components
    • Added visibilityAtHeight prop to control element visibility based on viewport/container height breakpoints
  • Documentation

    • Added new examples demonstrating vertical OverflowMenu and Toolbar configurations
    • Added documentation for height-based responsive breakpoint behavior

@kmcfaul kmcfaul marked this pull request as draft April 10, 2026 17:13
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

Walkthrough

This PR adds height-responsive breakpoint support to OverflowMenu and Toolbar components. OverflowMenu gains an isVertical prop with height-based breakpoint evaluation and two new examples. Toolbar components (ToolbarContent, ToolbarGroup, ToolbarItem) gain a visibilityAtHeight prop for height-based visibility control, with a new vertical toolbar example and documentation.

Changes

Cohort / File(s) Summary
OverflowMenu Core
packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx
Added optional isVertical prop to control width vs. height breakpoint evaluation; refactored resize handling into separate handleResizeWidth and handleResizeHeight paths; added runtime error handling for missing breakpoint values.
OverflowMenu Examples
packages/react-core/src/components/OverflowMenu/examples/OverflowMenuSimpleVertical.tsx, packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx
New example components demonstrating vertical orientation with responsive breakpoints and container height-based breakpoint references.
OverflowMenu Documentation
packages/react-core/src/components/OverflowMenu/examples/OverflowMenu.md
Added sections for new vertical and container height examples; clarified existing "Breakpoint on container" example to specify "width".
Toolbar Components
packages/react-core/src/components/Toolbar/ToolbarContent.tsx, packages/react-core/src/components/Toolbar/ToolbarGroup.tsx, packages/react-core/src/components/Toolbar/ToolbarItem.tsx
Added visibilityAtHeight prop to each component; updated PageContext consumption to include height and getVerticalBreakpoint; applied height-based breakpoint modifier classes alongside existing width-based visibility.
Toolbar Documentation & Examples
packages/react-core/src/components/Toolbar/examples/Toolbar.md, packages/react-core/src/components/Toolbar/examples/ToolbarVertical.tsx
Added documentation section for vertical toolbar with isVertical and visibilityAtHeight usage; new example component demonstrating vertical toolbar with height-responsive visibility groups and items.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • mcoker
  • lboehling
  • thatblindgeye
  • nicolethoen
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding support for responsive height-based visibility breakpoints to Toolbar and OverflowMenu components.
Linked Issues check ✅ Passed The pull request successfully implements all stated requirements: isVertical prop for OverflowMenu, visibilityAtHeight props for Toolbar components, and includes examples demonstrating the behavior.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the linked issue objectives: OverflowMenu isVertical support, Toolbar height-responsive visibility, and accompanying examples with documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@patternfly-build
Copy link
Copy Markdown
Collaborator

patternfly-build commented Apr 10, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx (1)

63-72: ⚠️ Potential issue | 🟠 Major

Recompute the breakpoint when isVertical or breakpoint props change.

handleResize() branches on isVertical (lines 79–86) to use either height or width calculations, but componentDidUpdate() only reruns the calculation when breakpointRef changes. Flipping isVertical after mount or changing the breakpoint prop leaves isBelowBreakpoint stale until a resize event fires.

Suggested fix
  componentDidUpdate(prevProps: Readonly<OverflowMenuProps>, prevState: Readonly<OverflowMenuState>): void {
    const reference = this.props.breakpointReference ? this.getBreakpointRef() : undefined;

    if (prevState.breakpointRef !== reference) {
      // To remove any previous observer/event listener from componentDidMount before adding a new one
      this.observer();
      this.setState({ breakpointRef: reference });
      this.observer = getResizeObserver(reference, this.handleResizeWithDelay);
      this.handleResize();
+    } else if (
+      prevProps.isVertical !== this.props.isVertical ||
+      prevProps.breakpoint !== this.props.breakpoint
+    ) {
+      this.handleResize();
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx` around
lines 63 - 72, componentDidUpdate currently only reacts to breakpointRef changes
and so flipping isVertical or changing breakpoint leaves isBelowBreakpoint
stale; update componentDidUpdate (in OverflowMenu) to also detect prop changes
(prevProps.isVertical !== this.props.isVertical || prevProps.breakpoint !==
this.props.breakpoint) and when they change recompute the reference if needed
(use this.getBreakpointRef() like you do when computing reference) and call
this.handleResize() (and reattach observer if the breakpointReference-related
ref changed using this.observer = getResizeObserver(...)). Ensure you still call
this.observer() to cleanup and setState/update breakpointRef when the
breakpointReference-derived ref changes, but always invoke handleResize() when
isVertical or breakpoint props change so isBelowBreakpoint is updated
immediately.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx`:
- Around line 63-64: The displayed label text is wrong: in
OverflowMenuBreakpointOnContainerHeight.tsx update the span with id
"overflowMenu-hasBreakpointOnContainer-height-slider-label" (and any adjacent
text) from "Current container width" to "Current container height" (and ensure
any related aria/accessible labels or variables referencing containerHeight
reflect "height" consistently); keep the existing id and variable
containerHeight unchanged.
- Line 78: The example is using height-based breakpoint props but never toggles
OverflowMenu to vertical mode; update the <OverflowMenu> instance (the one with
props breakpointReference={containerRef} breakpoint="sm") to also pass
isVertical so OverflowMenu uses clientHeight for breakpoints, and change the
slider label text currently reading "Current container width" (around the slider
at line ~63) to "Current container height" so the UI and docs match the
height-based example.

In `@packages/react-core/src/components/Toolbar/examples/ToolbarVertical.tsx`:
- Around line 20-29: The example uses width-based props but should use height
breakpoints: replace the width-based visibility props with height-aware ones by
changing ToolbarGroup's visibility to visibilityAtHeight and each ToolbarItem's
visibility to visibilityAtHeight (i.e., keep the same breakpoint keys/values but
use visibilityAtHeight on ToolbarGroup and the two ToolbarItem instances with
lg/md/default as shown); update any prop names in ToolbarGroup and ToolbarItem
to visibilityAtHeight so the example demonstrates height breakpoints correctly.

---

Outside diff comments:
In `@packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx`:
- Around line 63-72: componentDidUpdate currently only reacts to breakpointRef
changes and so flipping isVertical or changing breakpoint leaves
isBelowBreakpoint stale; update componentDidUpdate (in OverflowMenu) to also
detect prop changes (prevProps.isVertical !== this.props.isVertical ||
prevProps.breakpoint !== this.props.breakpoint) and when they change recompute
the reference if needed (use this.getBreakpointRef() like you do when computing
reference) and call this.handleResize() (and reattach observer if the
breakpointReference-related ref changed using this.observer =
getResizeObserver(...)). Ensure you still call this.observer() to cleanup and
setState/update breakpointRef when the breakpointReference-derived ref changes,
but always invoke handleResize() when isVertical or breakpoint props change so
isBelowBreakpoint is updated immediately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4109d74c-080f-4724-9a72-c5cccf04a3cd

📥 Commits

Reviewing files that changed from the base of the PR and between 911223a and 08742ba.

📒 Files selected for processing (9)
  • packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx
  • packages/react-core/src/components/OverflowMenu/examples/OverflowMenu.md
  • packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx
  • packages/react-core/src/components/OverflowMenu/examples/OverflowMenuSimpleVertical.tsx
  • packages/react-core/src/components/Toolbar/ToolbarContent.tsx
  • packages/react-core/src/components/Toolbar/ToolbarGroup.tsx
  • packages/react-core/src/components/Toolbar/ToolbarItem.tsx
  • packages/react-core/src/components/Toolbar/examples/Toolbar.md
  • packages/react-core/src/components/Toolbar/examples/ToolbarVertical.tsx

Comment on lines +63 to +64
<span id="overflowMenu-hasBreakpointOnContainer-height-slider-label">Current container width</span>:{' '}
{containerHeight}%
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

The label still says width.

This is the height example, so the readout text is currently misleading.

🩹 Suggested fix
-          <span id="overflowMenu-hasBreakpointOnContainer-height-slider-label">Current container width</span>:{' '}
+          <span id="overflowMenu-hasBreakpointOnContainer-height-slider-label">Current container height</span>:{' '}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span id="overflowMenu-hasBreakpointOnContainer-height-slider-label">Current container width</span>:{' '}
{containerHeight}%
<span id="overflowMenu-hasBreakpointOnContainer-height-slider-label">Current container height</span>:{' '}
{containerHeight}%
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx`
around lines 63 - 64, The displayed label text is wrong: in
OverflowMenuBreakpointOnContainerHeight.tsx update the span with id
"overflowMenu-hasBreakpointOnContainer-height-slider-label" (and any adjacent
text) from "Current container width" to "Current container height" (and ensure
any related aria/accessible labels or variables referencing containerHeight
reflect "height" consistently); keep the existing id and variable
containerHeight unchanged.

/>
</div>
<div ref={containerRef} id="height-breakpoint-reference-container" style={containerStyles}>
<OverflowMenu breakpointReference={containerRef} breakpoint="sm">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the OverflowMenu.tsx file to verify the height logic
fd -t f "OverflowMenu.tsx" --path "*components/OverflowMenu*" | grep -v example

Repository: patternfly/patternfly-react

Length of output: 304


🏁 Script executed:

# Read the example file around line 78 to verify the prop usage
cat -n packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx | sed -n '70,85p'

Repository: patternfly/patternfly-react

Length of output: 906


🏁 Script executed:

# Check the OverflowMenu.tsx implementation around lines 79-116
cat -n packages/react-core/src/components/OverflowMenu/OverflowMenu.tsx | sed -n '75,120p'

Repository: patternfly/patternfly-react

Length of output: 1856


🏁 Script executed:

# Check the documentation file
fd -t f "OverflowMenu.md" --path "*OverflowMenu*"

Repository: patternfly/patternfly-react

Length of output: 304


🏁 Script executed:

# Check line 63 for the label issue
cat -n packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx | sed -n '60,70p'

Repository: patternfly/patternfly-react

Length of output: 506


🏁 Script executed:

# Find and read the OverflowMenu.md documentation
find . -name "OverflowMenu.md" -type f

Repository: patternfly/patternfly-react

Length of output: 145


🏁 Script executed:

# Search for documentation about the height breakpoint example
rg "breakpointReference.*isVertical|isVertical.*breakpointReference|container height" -A 3 -B 3 --type md packages/react-core/src/components/OverflowMenu/

Repository: patternfly/patternfly-react

Length of output: 1023


Pass isVertical here or this example never exercises the height breakpoint path.

OverflowMenu.tsx only switches to clientHeight/window.innerHeight when isVertical is set. As written, this "container height" example is still width-based, which conflicts with the documentation in OverflowMenu.md that explicitly states both breakpointReference and isVertical are required for height-based breakpoints.

Additionally, the slider label on line 63 says "Current container width" but should say "Current container height" for this example.

🩹 Suggested fix
-        <OverflowMenu breakpointReference={containerRef} breakpoint="sm">
+        <OverflowMenu breakpointReference={containerRef} breakpoint="sm" isVertical>

Also update line 63 label from "Current container width" to "Current container height".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<OverflowMenu breakpointReference={containerRef} breakpoint="sm">
<OverflowMenu breakpointReference={containerRef} breakpoint="sm" isVertical>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/react-core/src/components/OverflowMenu/examples/OverflowMenuBreakpointOnContainerHeight.tsx`
at line 78, The example is using height-based breakpoint props but never toggles
OverflowMenu to vertical mode; update the <OverflowMenu> instance (the one with
props breakpointReference={containerRef} breakpoint="sm") to also pass
isVertical so OverflowMenu uses clientHeight for breakpoints, and change the
slider label text currently reading "Current container width" (around the slider
at line ~63) to "Current container height" so the UI and docs match the
height-based example.

Comment on lines +20 to +29
<ToolbarGroup variant="action-group-plain" visibility={{ default: 'hidden', md: 'visible' }}>
<ToolbarItem>
<Button variant="plain" aria-label="edit" icon={<EditIcon />} />
</ToolbarItem>
<ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="clone" icon={<CloneIcon />} />
</ToolbarItem>
<ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="sync" icon={<SyncIcon />} />
</ToolbarItem>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use visibilityAtHeight here; visibility is width-based.

This example is meant to demonstrate height breakpoints, but the current props are width-responsive only.

Proposed fix
-      <ToolbarGroup variant="action-group-plain" visibility={{ default: 'hidden', md: 'visible' }}>
+      <ToolbarGroup variant="action-group-plain" visibilityAtHeight={{ default: 'hidden', md: 'visible' }}>
         <ToolbarItem>
           <Button variant="plain" aria-label="edit" icon={<EditIcon />} />
         </ToolbarItem>
-        <ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
+        <ToolbarItem visibilityAtHeight={{ default: 'hidden', lg: 'visible' }}>
           <Button variant="plain" aria-label="clone" icon={<CloneIcon />} />
         </ToolbarItem>
-        <ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
+        <ToolbarItem visibilityAtHeight={{ default: 'hidden', lg: 'visible' }}>
           <Button variant="plain" aria-label="sync" icon={<SyncIcon />} />
         </ToolbarItem>
       </ToolbarGroup>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<ToolbarGroup variant="action-group-plain" visibility={{ default: 'hidden', md: 'visible' }}>
<ToolbarItem>
<Button variant="plain" aria-label="edit" icon={<EditIcon />} />
</ToolbarItem>
<ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="clone" icon={<CloneIcon />} />
</ToolbarItem>
<ToolbarItem visibility={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="sync" icon={<SyncIcon />} />
</ToolbarItem>
<ToolbarGroup variant="action-group-plain" visibilityAtHeight={{ default: 'hidden', md: 'visible' }}>
<ToolbarItem>
<Button variant="plain" aria-label="edit" icon={<EditIcon />} />
</ToolbarItem>
<ToolbarItem visibilityAtHeight={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="clone" icon={<CloneIcon />} />
</ToolbarItem>
<ToolbarItem visibilityAtHeight={{ default: 'hidden', lg: 'visible' }}>
<Button variant="plain" aria-label="sync" icon={<SyncIcon />} />
</ToolbarItem>
</ToolbarGroup>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-core/src/components/Toolbar/examples/ToolbarVertical.tsx`
around lines 20 - 29, The example uses width-based props but should use height
breakpoints: replace the width-based visibility props with height-aware ones by
changing ToolbarGroup's visibility to visibilityAtHeight and each ToolbarItem's
visibility to visibilityAtHeight (i.e., keep the same breakpoint keys/values but
use visibilityAtHeight on ToolbarGroup and the two ToolbarItem instances with
lg/md/default as shown); update any prop names in ToolbarGroup and ToolbarItem
to visibilityAtHeight so the example demonstrates height breakpoints correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Toolbar/OverflowMenu - responsive height breakpoints for show/hide

2 participants