DEV Community

Talisson
Talisson

Posted on

BulkActionsBar - Part 2 - Engineering a Robust and Accessible Bulk Actions Bar in React

In Part 1, we explored how micro-interactions elevate the user experience of a Bulk Actions Bar. In this article, we’ll dive into the technical engineering challenges that made those interactions possible while ensuring flexibility, performance, and accessibility.

Overflow Detection: Calculating Visible Items

One of the first hurdles was determining how many buttons could fit inline based on container width. CSS alone wasn’t sufficient.

I built a custom hook useVisibleChildrenCount using ResizeObserver to dynamically calculate the number of visible items:

export function useVisibleChildrenCount({ containerEl, isEnabled, gap = 0 }) {
  const [visibleCount, setVisibleCount] = useState(0)

  const measureVisibleItems = useCallback(() => {
    if (!containerEl) return

    const childrenEls = Array.from(containerEl.children).filter(
      (el) => el instanceof HTMLDivElement
    )

    let totalWidth = 0
    let fitCount = 0

    for (let i = 0; i < childrenEls.length; i++) {
      const childWidth = childrenEls[i].offsetWidth
      const spaceRequired = totalWidth === 0 ? childWidth : childWidth + gap

      if (totalWidth + spaceRequired <= containerEl.offsetWidth) {
        totalWidth += spaceRequired
        fitCount += 1
      } else {
        break
      }
    }

    setVisibleCount(fitCount)
  }, [containerEl, gap])

  useEffect(() => {
    if (!isEnabled || !containerEl) return

    const observer = new ResizeObserver(() => {
      window.requestAnimationFrame(measureVisibleItems)
    })

    observer.observe(containerEl)
    measureVisibleItems()

    return () => observer.disconnect()
  }, [containerEl, isEnabled, measureVisibleItems])

  return isEnabled ? visibleCount : containerEl?.children.length || 0
}
Enter fullscreen mode Exit fullscreen mode

This hook allowed the component to adapt in real-time as container dimensions changed.

The Dropdown Menu: Desktop vs Mobile Submenus

Calendly uses react-aria-components for accessible menus. Handling nested submenus that behave differently on desktop and mobile introduced challenges:

  • MenuTrigger/MenuContent structure is rigid.
  • Mobile submenus needed to stack as overlays.
  • Submenu depth was dynamic and recursive.

Attempt #1: Portal in Dropdown Item

In our first approach, we tried rendering submenus into a portal placed inside the dropdown menu item itself. The idea was to leverage a portal to visually stack submenus while keeping the parent menu open. However, React Aria’s strict DOM structure and focus management expectations made this unfeasible, as it broke assumptions about where menu content should exist in the hierarchy.

Attempt #2: Root Content Replacement with Stack State

The final solution was to manage a submenu stack state within MenuContent, where the active submenu would replace the root content entirely. On mobile, when a submenu is triggered, we swapped the root content node with the submenu node, simulating a page stack experience. This allowed us to preserve React Aria’s accessibility features while giving us full control over the submenu transitions.

Center Alignment with Side Navigation Constraints

Calendly’s main product has a persistent left sidebar, which shifted the content area. My initial implementation of the BulkActionsBar was viewport-centered, which appeared misaligned.

To fix this, we adopted an “Outlet Pattern”:

  1. Render a wrapper Outlet component aligned to the main content area.
  2. Pass a ref to this Outlet.
  3. Use a portal strategy to render the BulkActionsBar into this outlet.

This approach ensured visual alignment regardless of sidebar presence.

Recursive Submenus Handling

Managing recursive submenus required handling focus, depth stacking, and keyboard navigation without assumptions on submenu levels. I designed a recursive rendering strategy that adapted based on context:

  • On desktop: inline flyouts.
  • On mobile: stacked overlays.

Keyboard focus was managed dynamically, ensuring a seamless navigation experience across varying depths.

Lessons Learned

  • Small UI components can introduce significant architectural considerations.
  • Design system constraints demand flexible yet robust engineering solutions.
  • Accessibility cannot be an afterthought—it's foundational to component architecture.

Conclusion

Engineering a flexible BulkActionsBar required a blend of creative problem-solving and meticulous attention to UX and accessibility details. It exemplifies how thoughtful component design goes beyond visual styling, intersecting architecture, user flows, and real-world product constraints.


References:


Special thanks to the Calendly Design Systems Team for the collaborative ideation and problem-solving sessions that made this component possible.

Top comments (0)