Menus
CollapsibleMenu
CollapsibleMenu moves the items that don’t fit into an overflow popover, opened by a “Meny” button. Use it for responsive navigation bars and headers. Its items can be any elements: links, buttons or VerticalMenus.
---
import { CollapsibleMenu } from "@dynamic-type/ddi/server";
---
<header class="x-flow items:center p bg rounded inline-size:100cqi">
<div class="p bg:alt rounded">Logo</div>
<CollapsibleMenu
class="flex:1"
buttonClass="bg:alt"
overflowItemsClass="rounded drop-shadow"
>
<a href="#item-1" class="button tertiary">Item 1</a>
<a href="#item-2" class="button tertiary">Item 2</a>
<a href="#item-3" class="button tertiary">Item 3</a>
<a href="#item-4" class="button tertiary">Item 4</a>
<a href="#item-5" class="button tertiary">Item 5</a>
<a href="#item-6" class="button tertiary">Item 6</a>
<a href="#item-7" class="button tertiary">Item 7</a>
<a href="#item-8" class="button tertiary">Item 8</a>
</CollapsibleMenu>
</header>Set collapseAll to move every item into the overflow menu as soon as one of them doesn’t fit.
---
import { CollapsibleMenu } from "@dynamic-type/ddi/server";
---
<header class="x-flow items:center p bg rounded inline-size:100cqi">
<div class="p bg:alt rounded">Logo</div>
<CollapsibleMenu class="flex:1" collapseAll>
<a href="#item-1" class="button tertiary">Item 1</a>
<a href="#item-2" class="button tertiary">Item 2</a>
<a href="#item-3" class="button tertiary">Item 3</a>
<a href="#item-4" class="button tertiary">Item 4</a>
<a href="#item-5" class="button tertiary">Item 5</a>
<a href="#item-6" class="button tertiary">Item 6</a>
<a href="#item-7" class="button tertiary">Item 7</a>
<a href="#item-8" class="button tertiary">Item 8</a>
</CollapsibleMenu>
</header>Fold order and an icons-only button
Items fold from the right. Mark an item data-ddi-collapse-last to keep it out of the overflow menu as long as there is room for it: it folds only after every other item has. With collapseAll, all the other items fold at once, then the collapse-last items fold one at a time from the right.
With buttonIcons, the button shows copies of the folded items’ icons (the child marked data-ddi-menu-icon) and no text. buttonLabel becomes its aria-label.
An item that opens a popover with data-ddi-popovertarget opens it from the overflow button while it is folded. That also applies to a script calling item.click(). The overflow menu closes, and the popover is placed with the button’s buttonAlign and offsets.
---
import { CollapsibleMenu, Popover } from "@dynamic-type/ddi/server";
const tools = [
{ name: "Compare", d: "M4 6h16M4 12h16M4 18h16" },
{
name: "Search",
d: "M11 4a7 7 0 1 0 0 14a7 7 0 0 0 0-14ZM16 16l4 4",
last: true,
},
{
name: "Settings",
d: "M12 4v16M4 12h16",
popover: "icons-example-settings",
},
{
name: "Account",
d: "M12 4a4 4 0 1 0 0 8a4 4 0 0 0 0-8ZM4 20a8 8 0 0 1 16 0",
},
];
---
<header class="x-flow items:center p bg rounded inline-size:100cqi">
<div class="p bg:alt rounded">Logo</div>
<div class="flex:1">John 3</div>
<CollapsibleMenu
collapseAll
buttonIcons
buttonLabel="Menu"
buttonAlign="top-center"
>
{
tools.map(({ name, d, last, popover }) => (
<button
class="tertiary y-flow items:center"
data-ddi-collapse-last={last}
data-ddi-popovertarget={popover}
>
<svg
data-ddi-menu-icon
viewBox="0 0 24 24"
width="20"
height="20"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path d={d} />
</svg>
{name}
</button>
))
}
</CollapsibleMenu>
</header>
<Popover id="icons-example-settings" class="p bg rounded drop-shadow">
Settings
</Popover>When it re-measures
The menu re-measures whenever the menu, its parent, an item or the button changes size. That covers text size, a changed label and a hidden menu being shown. It also re-measures on window resize and once web fonts have loaded. Each measurement restores every item to the row, measures it and folds again in the same frame, so a wider row brings items back.
It never folds while a pointer is down in the menu or while the overflow menu is open. It waits for the pointer to lift or the menu to close.
For changes no observer sees, call menu.refresh() or dispatch ddi:collapsible-refresh on the menu.
Items keep their size in the row (flex-shrink: 0), and the menu takes whatever room its parent gives it. In a flex row where another item shrinks too, flex shrinks both together, so the menu starts folding before the other item has given up its room. To make the other item shrink first, give it a large flex-shrink and a min-inline-size (e.g. flex: 0 1000 auto), and the menu flex: 0 1 auto; min-inline-size: 0.
Items with display: none are not measured and never folded.
Props
collapseAll- Fold all items (exceptdata-ddi-collapse-lastones) at once when any of them overflowbuttonIcons- The default button shows the folded items’ icons instead of textbuttonLabel- Text of the default button, or itsaria-labelwithbuttonIcons(default “Meny”)buttonAlign,buttonOffsetX,buttonOffsetY-data-ddi-alignanddata-ddi-offset-*of the default button. They are rendered on the server along withdata-ddi-popovertarget, so page scripts see them at loadbuttonClass- Classes for the overflow menu buttonoverflowItemsClass- Classes for the container of the overflow itemsvisibleItemsClass- Classes for the container of the visible itemsmenuItemsClass- Deprecated, useoverflowItemsClassclass- Classes for the root element
Attributes
data-ddi-collapse-last(on an item) - Fold this item only after all othersdata-ddi-menu-icon(inside an item) - The iconbuttonIconsshowsdata-ddi-overflowed(set on folded items) - Style rows in the overflow menu with[data-ddi-overflowed]
Events and methods
ddi:collapsible-change- Fired on the menu when the set of folded items changes.detail.overflowedlists them in item orderrefresh()/ddi:collapsible-refresh- Re-measure now
Slots
- default - The menu items. They are read once when the menu starts
overflow-menu-button- Replaces the default “Meny” button. It getsdata-ddi-popovertarget(and anid) from the client script
VerticalMenu
VerticalMenu is a button that opens its items in a popover. Use it for submenus and grouped actions.
---
import { VerticalMenu } from "@dynamic-type/ddi/server";
---
<VerticalMenu
name="Account"
buttonClass="bg:alt rounded"
itemsClass="rounded drop-shadow"
>
<a href="#dashboard" class="button tertiary">Dashboard</a>
<a href="#settings" class="button tertiary">Settings</a>
<a href="#profile" class="button tertiary">Profile</a>
<a href="#logout" class="button tertiary">Log out</a>
</VerticalMenu>Props
name- Text on the default button (required)unwrapPrefix- How items are labelled when the menu is unwrapped into aCollapsibleMenu’s overflow menu:false(default) - No prefixtrue- Prefix withname+ “ – “string- Prefix with the string + “ – “
buttonClass- Classes for the default buttonitemsClass- Classes for the container of the itemsclass- Classes for the root element
Slots
- default - The menu items
vertical-menu-button- Replaces the default button. It must have the classvertical-menu-button
Combining the two
When a CollapsibleMenu moves a VerticalMenu into its overflow menu, the vertical menu is unwrapped: its items are placed directly in the overflow menu. When it comes back into the row, it is wrapped again. With unwrapPrefix, each item keeps the submenu’s name, so “Design” becomes “Services – Design”.
---
import { CollapsibleMenu, VerticalMenu } from "@dynamic-type/ddi/server";
---
<header class="x-flow items:center p bg rounded inline-size:100cqi">
<div class="p bg:alt rounded">Logo</div>
<CollapsibleMenu class="flex:1" overflowItemsClass="rounded drop-shadow">
<a href="#item-1" class="button tertiary">Item 1</a>
<a href="#item-2" class="button tertiary">Item 2</a>
<VerticalMenu name="Services" unwrapPrefix>
<a href="#design" class="button tertiary">Design</a>
<a href="#development" class="button tertiary">Development</a>
<a href="#consulting" class="button tertiary">Consulting</a>
</VerticalMenu>
<a href="#item-3" class="button tertiary">Item 3</a>
<a href="#item-4" class="button tertiary">Item 4</a>
</CollapsibleMenu>
</header>