Action Sheet
Mobile action sheet: a bottom Drawer (native modal <dialog>, drag to dismiss, safe focus handling) whose actions follow the WAI-ARIA APG menu pattern.
| Package | @vizejs/ui/action-sheet |
| Maturity | stable |
| Own the source | vize lib pull action-sheet |
| Requires | context, dialog, drawer, id |
| Aliases | action sheet, bottom menu, share sheet, iOS action sheet |
| Covers | WAI-ARIA Menu, UIKit UIAlertController actionSheet, Ionic ActionSheet |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { ActionSheetMenu, ActionSheetItem } from "@vizejs/ui/action-sheet";
Or copy the source into your project with vize lib pull action-sheet (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Bottom action sheet offering photo actions, including a disabled and a destructive one. -->
<script setup lang="ts">
import { ref } from "vue";
import {
ActionSheet,
ActionSheetCancel,
ActionSheetContent,
ActionSheetDescription,
ActionSheetItem,
ActionSheetMenu,
ActionSheetTitle,
ActionSheetTrigger,
} from "@vizejs/ui/action-sheet";
import type { ActionSheetSelectEvent } from "@vizejs/ui/action-sheet";
const open = ref(false);
const chosen = ref<string | null>(null);
function onSelect(event: ActionSheetSelectEvent): void {
chosen.value = event.value;
}
</script>
<template>
<div>
<ActionSheet v-model:open="open">
<ActionSheetTrigger>Photo options</ActionSheetTrigger>
<ActionSheetContent>
<ActionSheetTitle>Photo</ActionSheetTitle>
<ActionSheetDescription>Choose what to do with this photo.</ActionSheetDescription>
<ActionSheetMenu>
<ActionSheetItem value="share" @select="onSelect">Share</ActionSheetItem>
<ActionSheetItem value="copy" @select="onSelect">Copy link</ActionSheetItem>
<ActionSheetItem value="archive" disabled @select="onSelect">Archive</ActionSheetItem>
<ActionSheetItem value="delete" destructive @select="onSelect">Delete</ActionSheetItem>
</ActionSheetMenu>
<ActionSheetCancel>Cancel</ActionSheetCancel>
</ActionSheetContent>
</ActionSheet>
<output>Last action: {{ chosen ?? "none" }}</output>
</div>
</template>
API
ActionSheetMenu
Source: src/families/overlays/action-sheet/action-sheet-menu.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
loop |
boolean |
true |
Wrap arrow-key focus from the last action to the first and back. |
ariaLabel |
string |
undefined |
Accessible name when the sheet title should not label the menu. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
Record<string, never> |
ActionSheetItem actions (and optional ActionSheetCancel). |
ActionSheetItem
Source: src/families/overlays/action-sheet/action-sheet-item.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value (required) |
string |
required |
Action identifier reported by select. |
disabled |
boolean |
false |
Disable the action (skipped by arrow keys and typeahead, announced with aria-disabled). |
destructive |
boolean |
false |
Mark a destructive action for styling (data-destructive). |
textValue |
string |
the element's text content |
Text used for typeahead when the label is not plain text. |
Events
| Event | Payload | Description |
|---|---|---|
select |
[event: ActionSheetSelectEvent] |
Fired when the action is chosen; call preventDefault() to keep the sheet open. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ readonly disabled: boolean } |
Action label and icon. |
Behavior
Normative state x input -> outcome table for action-sheet-menu.vue and
action-sheet-item.vue (@vizejs/ui/action-sheet). The sheet container is the
Drawer (bottom side by default: native modal <dialog>, focus scope, drag to
dismiss, snap points), re-exported as ActionSheet, ActionSheetTrigger,
ActionSheetContent, ActionSheetTitle, ActionSheetDescription, and
ActionSheetCancel; the actions follow the WAI-ARIA APG menu pattern. Every row
is proven by the named test in action-sheet.test.ts or action-sheet-ssr.test.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| AS1 | closed | trigger click | a bottom Drawer opens; the role="menu" is labelled by the sheet title; the first enabled action is the tab stop; disabled/destructive hooks render |
opens a bottom sheet whose actions form a menu labelled by the title |
| AS2 | open | Arrow / Home / End / typeahead | roving focus moves between enabled actions, wraps with loop, and typeahead matches labels |
arrow keys, Home, End, and typeahead move a roving focus that skips disabled actions |
| AS3 | open | click / Enter / Space | select fires with a cancelable event; unless prevented the sheet closes; disabled actions never select |
selecting an action emits select and closes; preventDefault keeps the sheet open |
| AS4 | no provider | setup | the menu needs the Dialog context and items need the menu (VIZE_UI_CONTEXT_MISSING) |
menus and items require their providers |
| AS5 | SSR / hydration | isolated requests (defaultOpen) |
byte-identical menu markup with a deterministic tab stop and hydration without diagnostics | renders an open sheet's menu deterministically and hydrates without mismatches |
The subpath ships no CSS.