Skip to content

fix(shared): improve dropdown scroll affordance and responsive sizing#5673

Merged
idoshamun merged 3 commits intomainfrom
fix/shared-dropdown-scroll-and-sizing
Mar 9, 2026
Merged

fix(shared): improve dropdown scroll affordance and responsive sizing#5673
idoshamun merged 3 commits intomainfrom
fix/shared-dropdown-scroll-and-sizing

Conversation

@tsahimatsliah
Copy link
Member

@tsahimatsliah tsahimatsliah commented Mar 7, 2026

Summary

  • Add useScrollFade and wire it into shared DropdownMenuContent for top/bottom overflow fade indicators.
  • Replace fixed dropdown scroll height with viewport-aware sizing using --radix-dropdown-menu-content-available-height.
  • Add dropdown variants (action and field) to separate sizing behavior.
  • Improve action dropdown UX with readable default width and increased trigger gap (sideOffset).
  • Keep field/select menus trigger-width based, add a field global max-height clamp for long lists, and prevent tiny-width shrinking with a field min width floor.
  • Tune viewport edge safety by increasing dropdown collision padding to 24.
  • Tune fade behavior: edge opacity set to 0.24 and mask logic updated so edge items remain visible.
  • Compact dropdown item visuals by reducing row/icon density for a cleaner menu style.
  • Align select-like components (Dropdown, Select, PollDurationDropdown, MonthSelect, YearSelect, ExperienceLevelDropdown) with shared field variant behavior.

Test plan

  • Run pnpm --filter shared lint
  • Verify action dropdown spacing and width in feed/post context menus
  • Verify field/select dropdown width and height behavior on small and large screens
  • Verify long option lists (year select) keep visible edge items with fade and proper viewport gaps

Preview domain

https://fix-shared-dropdown-scroll-and-s.preview.app.daily.dev

Add Notion-style scroll fade cues for overflowing dropdowns, make action menus easier to read, and standardize field dropdown sizing so small triggers no longer collapse menu content.

Made-with: Cursor
@vercel
Copy link

vercel bot commented Mar 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
daily-webapp Ready Ready Preview Mar 7, 2026 1:15pm
storybook Building Building Preview Mar 7, 2026 1:15pm

Request Review

@tsahimatsliah
Copy link
Member Author

Implemented branch summary:

  • Added useScrollFade (packages/shared/src/hooks/useScrollFade.ts) and integrated it in shared DropdownMenuContent so overflowing menus show top/bottom fade affordances.
  • Replaced fixed dropdown scroll height with viewport-aware sizing: max-h-[var(--radix-dropdown-menu-content-available-height)].
  • Added dropdown variants for width behavior:
    • action: readable menu sizing defaults for action/context menus.
    • field: trigger-width behavior for select-like controls, with viewport clamp.
  • Added global field-menu height clamp for long option lists:
    • .DropdownMenuContentField .DropdownMenuScrollable { max-height: min(var(--radix-dropdown-menu-content-available-height), 20rem); }
  • Tuned action dropdown trigger gap via default sideOffset for action variant.
  • Reduced dropdown row density and menu icon size for more compact Notion-like presentation.
  • Refined fade rendering so edge items remain visible (edge opacity set to 0.56) and removed the false "bottom gap" perception.
  • Normalized select-like components to the shared field variant behavior:
    • Dropdown, Select, PollDurationDropdown, MonthSelect, YearSelect, ExperienceLevelDropdown.

Validation completed:

  • pnpm --filter shared lint passes.

Adjust dropdown fade edge opacity and increase collision padding so constrained menus remain visible while keeping a safer gap from viewport edges.

Made-with: Cursor
@idoshamun
Copy link
Member

@claude what is this scroll fade hook introduced here? what is it used for?

@claude
Copy link
Contributor

claude bot commented Mar 9, 2026

Claude finished @idoshamun's task in 30s —— View job


useScrollFade — what it is and how it works

useScrollFade (packages/shared/src/hooks/useScrollFade.ts) is a small, DOM-based hook that adds top/bottom gradient fade indicators to any scrollable container, giving users a visual cue that there is more content to scroll to.


How it works

The hook returns a ref callback you attach to a scrollable element. Once attached, it:

  1. Observes the element — attaches a scroll event listener and a ResizeObserver so it reacts to both user scrolling and layout changes.
  2. Computes scroll state on each update (via requestAnimationFrame for batching):
    • canScrollUpscrollTop > 1
    • canScrollDownscrollTop + clientHeight < scrollHeight - 1
  3. Sets CSS custom properties directly on the element's style:
    • --scroll-fade-top / --scroll-fade-bottom: 2rem when there's more content in that direction, 0px when at the edge.
    • --scroll-fade-top-opacity / --scroll-fade-bottom-opacity: 0.24 at the scroll edge (semi-transparent), 1 when fully scrolled to that end.
  4. Cleans up listeners and the ResizeObserver when the element is detached or the component unmounts.

Those CSS variables are consumed by the .DropdownMenuScrollable class in style.css via a mask-image gradient:

mask-image: linear-gradient(
  to bottom,
  rgb(0 0 0 / var(--scroll-fade-top-opacity)) 0,
  black var(--scroll-fade-top),
  black calc(100% - var(--scroll-fade-bottom)),
  rgb(0 0 0 / var(--scroll-fade-bottom-opacity)) 100%
);

This creates a soft fade-out at the top/bottom of the list — showing that items exist beyond the visible area — without adding any extra DOM nodes.


Where it's wired in

DropdownMenuContent (packages/shared/src/components/dropdown/DropdownMenu.tsx:120) calls the hook and attaches the ref to the inner DropdownMenuScrollable div that wraps all menu children. Every dropdown in the app (action menus, field/select dropdowns) benefits from this automatically.


Summary

It's essentially a scroll affordance helper: a pure DOM hook that drives a CSS mask fade via custom properties to let users know a dropdown list is scrollable. No external dependencies, no extra DOM — just event listeners + ResizeObserver + CSS variables.

@idoshamun idoshamun merged commit 69c972e into main Mar 9, 2026
11 checks passed
@idoshamun idoshamun deleted the fix/shared-dropdown-scroll-and-sizing branch March 9, 2026 07:15
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.

2 participants