Skip to content

✨ feat: add disabled actions and openOnHover to VirtualizedTable.Actions - #715

Open
futjesus wants to merge 2 commits into
mainfrom
feat/table-actions-disabled-reason
Open

futjesus wants to merge 2 commits into
mainfrom
feat/table-actions-disabled-reason

Conversation

@futjesus

@futjesus futjesus commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

Upstreams behaviour the microfrontends had to reimplement on top of VirtualizedTable.Actions:

  • disabled / disabledReason per action: the item renders aria-disabled (still focusable for keyboard navigation) and, when a reason is given, shows it in a Tooltip. Replaces DisabledDeleteAction (vpc), VolumeActions.disabledReason (volumes) and the tooltip-wrapped disabled buttons in settings.
  • openOnHover={false}: click-only trigger for both the inline and the portal variant. Compute (InstanceActions) and volumes (VolumeActions) rewrote the whole menu just to get this.
  • No hover re-open after selecting an action until the pointer leaves the trigger. In the inline variant the panel stayed visible after a click because the pointer was still inside the group (objectstore FileActionsCell had a pointer-events latch for this).

Notes

  • vi.unstubAllGlobals() in the portal test suite was removing the ResizeObserver stub from tests/setup.ts, which broke Radix Tooltip inside the menu. It now restores only innerHeight.
  • Stories (Light/Dark) include a disabled action with a reason.

Test plan

  • npx vitest run lib/components/VirtualizedTable (74 tests)
  • npm run lint, npm run check:types, prettier
  • Storybook: hover the disabled "Delete" action in the Actions column, check tooltip; check click-only behaviour by toggling openOnHover in a story

Actions can now be marked `disabled` or carry a `disabledReason`, which
renders the item as `aria-disabled` (still focusable for keyboard menu
navigation, per WAI-ARIA) with a tooltip explaining why the action is
unavailable. This replaces the local DisabledDeleteAction (vpc),
VolumeActions.disabledReason (volumes) and ActionsCell tooltip wrappers
(settings) in the microfrontends.

`openOnHover={false}` switches both the inline and the portal variant to a
click-only trigger, which compute and volumes implemented locally because
the menu previously only opened on hover.

After selecting an action, hover no longer re-reveals the menu until the
pointer leaves the trigger. In the inline variant the panel stayed visible
after a click because the pointer was still inside the `group`; the
objectstore microfrontend worked around it with a pointer-events latch.
The suppression reset lives on the trigger button rather than the wrapper
because React emulates pointerleave from the component tree, so the portal
menu counts as inside the wrapper.

The portal test suite no longer calls `vi.unstubAllGlobals()`, which was
removing the ResizeObserver stub from tests/setup.ts and broke Radix
Tooltip inside the menu.
`disabledReasonSide` can be set per action or once on `Actions` as the
default for every item. A `disabled` action without `disabledReason`
renders no tooltip at all; the tooltip is opt-in through `disabledReason`.
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.

1 participant