Skip to content

floatingUIOptions.useFloatingOptions completely overwrites internal settings instead of merging #2308

@ysds

Description

@ysds

Describe the bug

When passing floatingUIOptions={{ useFloatingOptions: { strategy: "fixed" } }} to components like FormattingToolbarController, SideMenuController, or LinkToolbarController, the internal useFloatingOptions settings (including open, onOpenChange, placement, and middleware) are completely overwritten instead of being merged. This causes the toolbar/menu to not appear at all.

To Reproduce

  1. Use a BlockNoteView inside a scrollable container
  2. Pass floatingUIOptions with useFloatingOptions.strategy: "fixed" to any controller:
<FormattingToolbarController
  floatingUIOptions={{
    useFloatingOptions: { strategy: "fixed" },
  }}
  formattingToolbar={() => <CustomFormattingToolbar />}
/>
  1. The formatting toolbar does not appear when selecting text

Expected behavior

The strategy: "fixed" option should be merged with the internal useFloatingOptions settings, preserving open, onOpenChange, placement, and middleware while adding/overriding only the strategy property.

Root cause

Looking at the source code in FormattingToolbarController:

const c = useMemo(
  () => ({
    useFloatingOptions: {
      open: o,
      onOpenChange: (a, u, d) => { /* ... */ },
      placement: i,
      middleware: [offset(10), shift(), flip()]
    },
    elementProps: { /* ... */ },
    ...e.floatingUIOptions  // <-- This spreads at the top level
  }),
  [/* ... */]
);

The spread ...e.floatingUIOptions replaces the entire useFloatingOptions object if provided, rather than merging nested properties.

Misc

  • Node version: 24.12.0
  • Package manager: npm
  • Browser: Chrome
  • I'm a sponsor and would appreciate if you could look into this sooner than later 💖

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions