Menu pane
A container that lets you drop a full interactive component (a Color picker, a slider or a small form) into a Menu, a Menu flyout submenu or a Context menu.
A plain Menu runs a roving focus zone: arrow keys move between its items and only one item sits in the tab order at a time. Wrapping custom content in a Menu pane opts that subtree out of the focus zone, so the embedded component keeps its own keyboard behavior. Arrow keys drive its sliders and steppers and Tab reaches every control. Arrow navigation across the surrounding menu items simply skips over the pane; reach it with Tab.
Clicking inside a pane never closes the menu, so the embedded component stays usable while the menu is open.
Slots
default
The custom content to embed in the menu, such as a color picker, slider or small form.
Examples
Color picker
Embed a full color picker in a menu flyout submenu. Drag the saturation field, use the sliders and type into the inputs without the menu interfering.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="bold"
label="Bold"/>
<FluxMenuItem
icon-leading="italic"
label="Italic"/>
<FluxMenuFlyout
icon="palette"
label="Text color">
<FluxMenu>
<FluxMenuPane>
<FluxColorPicker v-model="color"/>
</FluxMenuPane>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import { FluxColorPicker, FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxPane } from '@flux-ui/components';
import { ref } from 'vue';
const color = ref('#22c55e');
</script>Slider
A single control such as a slider. Focus it with Tab, then the arrow keys adjust the value instead of moving between menu items.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="moon"
label="Night shift"/>
<FluxMenuFlyout
icon="sun"
label="Brightness">
<FluxMenu>
<FluxMenuPane>
<FluxFormSlider
v-model="brightness"
aria-label="Brightness"
is-ticks-visible/>
</FluxMenuPane>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import { FluxFormSlider, FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxPane } from '@flux-ui/components';
import { ref } from 'vue';
const brightness = ref(60);
</script>Range slider
A two-thumb range. Each thumb is its own focus stop and the arrow keys move it without disturbing the menu.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="arrow-down-a-z"
label="Sort"/>
<FluxMenuFlyout
icon="money-bill"
label="Price range">
<FluxMenu>
<FluxMenuPane>
<FluxFormRangeSlider
v-model="price"
is-ticks-visible
:max="1000"
:min="0"
:step="50"/>
</FluxMenuPane>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import { FluxFormRangeSlider, FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxPane } from '@flux-ui/components';
import { ref } from 'vue';
const price = ref<[number, number]>([200, 800]);
</script>Text area
A multi-line input. Typing, Enter and the arrow keys for the caret all stay inside the field.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="star"
label="Add to favorites"/>
<FluxMenuFlyout
icon="message"
label="Add note">
<FluxMenu>
<FluxMenuPane>
<FluxFormTextArea
v-model="note"
placeholder="Write a note..."
:rows="3"/>
</FluxMenuPane>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import { FluxFormTextArea, FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxPane } from '@flux-ui/components';
import { ref } from 'vue';
const note = ref('');
</script>Filter
A search field that filters the items below it. Typing (including the arrow keys for the caret) stays inside the input.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="plus"
label="New file"/>
<FluxMenuFlyout
icon="filter"
label="Actions">
<FluxMenu>
<FluxMenuPane>
<FluxFormInput
v-model="query"
type="search"
icon-leading="magnifying-glass"
placeholder="Filter actions..."/>
</FluxMenuPane>
<FluxMenuGroup>
<FluxMenuItem
v-for="action of filtered"
:key="action.label"
:icon-leading="action.icon"
:label="action.label"/>
<FluxMenuSubHeader
v-if="filtered.length === 0"
label="No matches"/>
</FluxMenuGroup>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import type { FluxIconName } from '@flux-ui/types';
import { FluxFormInput, FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxMenuSubHeader, FluxPane } from '@flux-ui/components';
import { computed, ref } from 'vue';
const actions: { readonly icon: FluxIconName; readonly label: string; }[] = [
{icon: 'scissors', label: 'Cut'},
{icon: 'copy', label: 'Copy'},
{icon: 'paste', label: 'Paste'},
{icon: 'clone', label: 'Duplicate'},
{icon: 'pen', label: 'Rename'},
{icon: 'trash', label: 'Delete'}
];
const query = ref('');
const filtered = computed(() => actions.filter(action => action.label.toLowerCase().includes(query.value.toLowerCase())));
</script>Settings
Several controls in one pane. Tab reaches every toggle, and toggling one never closes the menu.
<template>
<FluxPane style="width: 240px">
<FluxMenu>
<FluxMenuGroup>
<FluxMenuItem
icon-leading="user"
label="Account"/>
<FluxMenuFlyout
icon="bell"
label="Notifications">
<FluxMenu>
<FluxMenuPane>
<label style="display: flex; align-items: center; justify-content: space-between; gap: 12px">
Email
<FluxToggle v-model="email"/>
</label>
<label style="display: flex; align-items: center; justify-content: space-between; gap: 12px">
Push
<FluxToggle v-model="push"/>
</label>
</FluxMenuPane>
</FluxMenu>
</FluxMenuFlyout>
</FluxMenuGroup>
</FluxMenu>
</FluxPane>
</template>
<script
lang="ts"
setup>
import { FluxMenu, FluxMenuFlyout, FluxMenuGroup, FluxMenuItem, FluxMenuPane, FluxPane, FluxToggle } from '@flux-ui/components';
import { ref } from 'vue';
const email = ref(true);
const push = ref(false);
</script>