Background
Codex has 4 components so far that use the Menu component internally to provide a dropdown menu of options. These components are:
- Select
- Combobox
- Lookup
- TypeaheadSearch
For the first 3 components, we need to use FloatingUI's useFloating composable to implement positioning features and styles. Ideally, this implementation would be easily extensible to future components that use Menu.
We will not implement FloatingUI in TypeaheadSearch at this time: it should not need any of its features due to its single use in the header in Vector, and will only increase the size of the codex-search package.
Requirements
This task covers only menu positioning and horizontal sizing. Further features will be implemented in other tasks. For this task:
Menus should:
- Always remain "attached" to their triggering element
- Always have an appropriate width (e.g. in most cases, menus are the width of their triggering element)
- Be able to extend past the bounds of their container (e.g. a dialog)
This should all work:
- With scrolling
- With window resizing
- In LTR and RTL
Implementation details
- Use the floatingStyles object returned by useFloating() to position the menu. This includes:
- position: floatingStyles.position
- top: floatingStyles.top
- right: unset (needed for RTL contexts; no-flip)
- left: floatingStyles.left (no-flip)
- transform: floatingStyles.transform
- Use the size middleware to set the width of the menu
- Use the hide middleware to hide the menu when its triggering element is out of view, and to set the menu's visibility in CSS
- Use autoUpdate to recalculate position styles in reaction to certain changes
- Remove most of the code that previously positioned menus within dialogs, except setting position: static on the parent component when inside a dialog
Code sharing
The above proof-of-concept implements useFloating() for the Select component. We should implement it with a second component, then determine if there is enough repeated code to warrant a custom composable within Codex that implements useFloating() in a standard way that is sharable across menu components.
Open questions
- Drop-shadow buffer: OOUI's ClippableElement implemented a 7px buffer to account for off-by-one-pixel errors and to add space for drop-shadows. Do we also want a buffer and, if so, what size?
Acceptance criteria
- For Select, Combobox, and Lookup:
- The dropdown menu is the expected width (equal to its triggering element)
- The dropdown menu is properly placed below the triggering element
- The dropdown menu always remains "attached" to its triggering element, including on scroll and window resize
- This works for components inside or outside of a Dialog
- This works in LTR and RTL


