Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
63205ca
Replace portals with Popover API for layering
NullVoxPopuli Apr 10, 2026
6bfaa23
Fix popover UA style overrides
NullVoxPopuli Apr 10, 2026
bd5078f
Use dialog element for nested popover in demo
NullVoxPopuli Apr 10, 2026
84a1371
Fix nested popover stacking order
NullVoxPopuli Apr 11, 2026
b949def
Add disabled button tooltip demo
NullVoxPopuli Apr 11, 2026
1414c9b
Remove unnecessary @as="dialog" from tooltip demo
NullVoxPopuli Apr 11, 2026
cc04684
Always use <dialog> for Content element
NullVoxPopuli Apr 11, 2026
64147ea
Fix CI: add pnpm i -f to Setup job + update tooltip demo copy
NullVoxPopuli Apr 11, 2026
d129b61
Fix lint: add blank line before if statement
NullVoxPopuli Apr 11, 2026
b08c166
Fix CI: ensure ember-tsc binary exists before build
NullVoxPopuli Apr 11, 2026
a40e948
Style tooltip demo: center button, match floatybit style
NullVoxPopuli Apr 11, 2026
b78325c
Fix dark mode styles for header demo
NullVoxPopuli Apr 11, 2026
f95f6cc
Match dark mode colors to site palette
NullVoxPopuli Apr 11, 2026
3f19766
Switch Content back to <div> from <dialog>
NullVoxPopuli Apr 11, 2026
8cc83f0
Restore @as arg for Content element
NullVoxPopuli Apr 11, 2026
3f644cc
Address PR review comments + add migration guide
NullVoxPopuli Apr 12, 2026
2a65cfd
Auto-focus popover content with tabindex after showPopover
NullVoxPopuli Apr 12, 2026
f018c5c
Address review: auto-add open for @as="dialog", fix migration docs
NullVoxPopuli Apr 12, 2026
3816d65
Fix migration diff: PortalTargets is from portal-targets, not popover
NullVoxPopuli Apr 12, 2026
b7a31a1
Fix Menu focus in top layer
NullVoxPopuli Apr 12, 2026
5bcc058
Use requestAnimationFrame with isConnected check for focus
NullVoxPopuli Apr 12, 2026
2b357a0
Move focus management from Popover to Menu
NullVoxPopuli Apr 12, 2026
8412b8e
Use popover toggle event for Menu focus instead of Promise.resolve
NullVoxPopuli Apr 12, 2026
08d88ab
Add MDN link for toggle event
NullVoxPopuli Apr 12, 2026
33b1093
Remove PortalTargets from Menu docs + add migration guide
NullVoxPopuli Apr 12, 2026
dd40018
Fix CI: add pnpm i -f before build in Lint job
NullVoxPopuli Apr 12, 2026
a54b2fb
Clarify CSS considerations refer to [popover] attribute, not <dialog>
NullVoxPopuli Apr 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- uses: wyvox/action@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- run: pnpm i -f # ensure all bin symlinks are created
- run: pnpm build
- id: set-pending
run: echo "pending=$(./cache-status.sh)" >> $GITHUB_OUTPUT
Expand All @@ -47,6 +48,7 @@ jobs:
- uses: wyvox/action@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- run: pnpm i -f # ensure all bin symlinks are created
- run: pnpm build
- run: pnpm i -f # sync for some reason isn't running before lint
- run: ls -la ember-primitives/
Expand Down
79 changes: 55 additions & 24 deletions docs-app/app/templates/5-floaty-bits/menu.gjs.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
# Menu

Menus are built with Popovers, with added features for keyboard navigation and accessibility.
Menus are built with Popovers, with added features for keyboard navigation and accessibility.

The placement of the menu content is handled by `<Popover>`, so `<Menu>` accepts the same arguments for positioning the dropdown.

Like `<Popover>`, the `<Menu>` component uses portals in a way that totally solves layering issues. No more worrying about tooltips on varying layers of your UI sometimes appearing behind other floaty bits. See the `<Portal>` and `<PortalTargets>` pages for more information.
Like `<Popover>`, the `<Menu>` component uses the [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) for layering, which totally solves z-index and overflow clipping issues, no portals needed.

<div class="featured-demo">

```gjs live preview no-shadow
import { PortalTargets, Menu } from 'ember-primitives';
import { Menu } from "ember-primitives";

<template>
<PortalTargets />

<Menu @offsetOptions={{8}} as |m|>
<m.Trigger class="trigger" aria-label="Options">
<EllipsisVertical />
Expand All @@ -38,7 +36,11 @@ import { PortalTargets, Menu } from 'ember-primitives';
border: none;
font-size: 14px;
z-index: 10;
box-shadow: 0 0 #0000, 0 0 #0000, 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
box-shadow:
0 0 #0000,
0 0 #0000,
0 10px 15px -3px rgb(0 0 0 / 0.1),
0 4px 6px -4px rgb(0 0 0 / 0.1);
display: flex;
flex-direction: column;
}
Expand All @@ -50,7 +52,8 @@ import { PortalTargets, Menu } from 'ember-primitives';
cursor: pointer;
}

.content [role="menuitem"]:focus, .trigger:hover {
.content [role="menuitem"]:focus,
.trigger:hover {
background-color: #f9fafb;
}

Expand Down Expand Up @@ -79,16 +82,20 @@ import { PortalTargets, Menu } from 'ember-primitives';
</template>

const EllipsisVertical = <template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 512" fill="currentColor"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/></svg>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 128 512"
fill="currentColor"
><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path
d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"
/></svg>
</template>;
```

</div>


Sometimes, you need to use an existing component as the trigger. `<Menu>` also yields a `trigger` modifier that you can use anywhere, even on your own components (e.g a custom button):


```hbs
<Menu as |m|>
<MyButton {{m.trigger}}>
Expand All @@ -106,25 +113,23 @@ Sometimes, you need to use an existing component as the trigger. `<Menu>` also y

Keep in mind that for the modifier to do its work, your custom component must use [`...attributes`](https://guides.emberjs.com/v5.7.0/components/component-arguments-and-html-attributes/#toc_html-attributes) in some HTML element.


## Install


```hbs live
<SetupInstructions @src="components/menu.gts" />
```


## API Reference

```gjs live no-shadow
import { ComponentSignature } from 'kolay';
import { ComponentSignature } from "kolay";

<template>
<ComponentSignature
@package="ember-primitives"
@module="declarations/components/menu"
@name="Signature" />
<ComponentSignature
@package="ember-primitives"
@module="declarations/components/menu"
@name="Signature"
/>
</template>
```

Expand All @@ -134,9 +139,35 @@ Adheres to the [Menu Button WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA

### Keyboard Interactions

| key | description |
| :---: | :----------- |
| <kbd>Space</kbd> <kbd>Enter</kbd> | When focus is on `Trigger`, opens the menu and focuses the first item. When focus is on an `Item`, activates the focused item. |
| <kbd>ArrowDown</kbd> <kbd>ArrowRight</kbd> | When `Content` is open, moves to the next item. |
| <kbd>ArrowUp</kbd> <kbd>ArrowLeft</kbd> | When `Content` is open, moves to the previous item. |
| <kbd>Esc</kbd> | Closes the menu and moves focus to `Trigger`. |
| key | description |
| :----------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------- |
| <kbd>Space</kbd> <kbd>Enter</kbd> | When focus is on `Trigger`, opens the menu and focuses the first item. When focus is on an `Item`, activates the focused item. |
| <kbd>ArrowDown</kbd> <kbd>ArrowRight</kbd> | When `Content` is open, moves to the next item. |
| <kbd>ArrowUp</kbd> <kbd>ArrowLeft</kbd> | When `Content` is open, moves to the previous item. |
| <kbd>Esc</kbd> | Closes the menu and moves focus to `Trigger`. |

## Migrating from <= v0.55

### Remove `<PortalTargets />`

`<Menu>` now uses the browser's Popover API for layering. You no longer need `<PortalTargets />` in your templates.

```diff
- import { PortalTargets, Menu } from 'ember-primitives';
+ import { Menu } from 'ember-primitives/components/menu';

<template>
- <PortalTargets />
<Menu as |m|>
...
</Menu>
</template>
```

### Remove `@inline`

The `@inline` argument has been removed. Menu content now renders inline in the DOM and uses the Popover API for layering.

### CSS considerations

The `popover` HTML attribute has a browser UA stylesheet that adds default `border` and `overflow` styles to elements with `[popover]`. You may need to set `border: none` on your menu content if you don't want the browser's default `[popover]` border. The component resets `overflow: visible` automatically.
Loading
Loading