A mobile action sheet gives people a short list of context-specific choices without taking them away from the screen they are using. In this guide, we will build the pattern around a Vue state model, DOM Studio’s DomActionSheet, and a practical accessibility test path.
The finished result is a bottom-anchored action surface for commands such as sharing a project, duplicating a draft, or deleting an item. We will keep the choice set compact, make destructive actions unmistakable, and verify that the overlay behaves as a real modal interaction.
Table of contents
- Before you start
- 1. Decide whether an action sheet is the right pattern
- 2. Define a compact, stable action model
- 3. Render the mobile action sheet in the app overlay
- 4. Make dismissal and focus behavior testable
- 5. Treat destructive actions as a separate risk
- 6. Run the phone-first release check
- Your completed mobile action sheet
Before you start
We need a Vue application and DOM Studio’s Vue package. We also need one clear trigger, a small list of actions tied to that trigger, and a decision about which action, if any, is destructive. An action sheet is for choices that follow an intentional user action. It is not a substitute for a long settings panel, a navigation menu, or an unexpected error alert.
For mobile app work, start with the DOM Studio mobile primitives, which are designed around safe-area-aware app chrome, touch-sized controls, and bottom-oriented actions. Keep the action sheet in the overlay region of the app shell so it can visually sit above the current screen.
1. Decide whether an action sheet is the right pattern
Start from the item or screen that owns the commands. For example, a draft card can expose Share project, Duplicate screen, and Delete draft from one overflow button.
Expected result: Every row in the sheet acts on the same, already understood object. The user does not need to interpret a new workflow before choosing.
Use an action sheet when the user has initiated an action and now needs to choose among a few related outcomes. Keep the title brief, add a description only when context is genuinely missing, and avoid a scrollable list of options. If there are many destinations or complex filters, use a dedicated screen or another focused component instead.
Troubleshooting: If the sheet contains global navigation, account settings, and item actions together, split the interaction. A bottom navigation pattern or a settings stack will be easier to understand and test.

2. Define a compact, stable action model
Model actions as data so the sheet stays reusable across cards, list rows, and detail screens. Give each action a stable value, a user-facing label, and an optional description. Mark only data-destroying behavior with the danger variant.
<script setup>
import { ref } from 'vue';
const sheetOpen = ref(false);
const activeDraftId = ref(null);
const actions = [
{
label: 'Share project',
description: 'Open the device share flow',
value: 'share',
},
{
label: 'Duplicate screen',
value: 'duplicate',
},
{
label: 'Delete draft',
value: 'delete',
variant: 'danger',
},
];
function openDraftActions(draftId) {
activeDraftId.value = draftId;
sheetOpen.value = true;
}
</script>
Expected result: We can open the same sheet for any draft while retaining the ID needed by the eventual command handler.
Troubleshooting: Do not use the visible label as your application command. Labels change with product language and localization. Keep command logic keyed to the stable value and use the active item ID to target the operation.
3. Render the mobile action sheet in the app overlay
DOM Studio’s mobile example uses DomActionSheet with v-model, a title, a description, and an actions array. Place it in the overlay slot of DomAppShell, rather than inside a scrolling list, so the sheet remains anchored to the app surface.
<script setup>
import { DomActionSheet, DomAppShell } from '@getdom/studio/vue';
</script>
<template>
<DomAppShell>
<main class="p-4">
<button type="button" @click="openDraftActions('draft-42')">
More actions
</button>
</main>
<template #overlay>
<DomActionSheet
v-model="sheetOpen"
title="Project actions"
description="Choose an action for this draft."
:actions="actions"
/>
</template>
</DomAppShell>
</template>
Expected result: Activating the button changes sheetOpen to true, and the action sheet appears over the current app view without moving the underlying content.
Troubleshooting: If the sheet appears inside the list or scrolls with its trigger, move the component to the app shell overlay. If you have multiple sheet triggers, keep one source of truth for the currently active item and open state.
For a full-screen mobile layout, pair this with DOM Studio’s app shell and mobile components. If the same product also needs responsive navigation, our Vue mobile navigation guide shows how we keep visual breakpoints in CSS and interaction state in Vue.
4. Make dismissal and focus behavior testable
A mobile action sheet is a modal surface. When it opens, keyboard focus should move into the modal. Tab and Shift+Tab should stay within it, Escape should close it, and focus should return to the element that opened it. The page behind the overlay must not remain interactive while the sheet is open.
We recommend this acceptance path for every implementation:
- Open the sheet with the trigger using a pointer, Enter, and Space.
- Confirm that initial focus is inside the sheet.
- Tab through all actionable controls, then Shift+Tab back through them.
- Press Escape and verify that focus returns to the trigger.
- Dismiss using the supplied cancel or backdrop behavior, then verify that no invisible overlay blocks the page.
Expected result: Keyboard users can complete or dismiss the interaction without losing their place, and assistive technology users are not sent into controls behind the sheet.
Troubleshooting: A dimmed backdrop alone does not create modality. If background controls can still receive focus or clicks, fix the component’s modal behavior before release. We also test with reduced motion enabled and ensure that focus remains visibly indicated.

5. Treat destructive actions as a separate risk
A delete action can live in the same mobile action sheet as non-destructive commands, but it needs a clearly different visual treatment and a safe next step. In the data model above, variant: 'danger' distinguishes the delete row from share and duplicate.
For an irreversible operation, let the action sheet select the intent and then use a confirmation step that names the affected item and the consequence. We should not force confirmation for harmless actions such as Share, but we should not make a destructive command easy to trigger accidentally either.
Expected result: A user can recognize the destructive path before it is completed, and our application only deletes activeDraftId after explicit confirmation.
Troubleshooting: If we need to explain several consequences, permissions, or recovery limitations, the action sheet is no longer the right surface for the final decision. Move that explanation into a confirmation dialog or dedicated screen.
6. Run the phone-first release check
Test the sheet on an actual narrow viewport, not only in a desktop browser. Check bottom safe-area spacing, long localized labels, text zoom, screen-reader navigation, and the keyboard if the screen includes editable fields. We also test the exact boundary where our app switches between desktop and mobile chrome.
Use this release checklist:
- The trigger is a real
<button>with an accessible name. - The sheet contains only related actions and does not require scrolling.
- Every action has a stable value for application logic.
- The destructive action is visually distinct and requires a safe follow-up when deletion is irreversible.
- Open, close, Escape, focus containment, and focus restoration all work.
- Backdrop dismissal does not leave a blocked or inert page behind.
- The sheet clears or updates its active item after the command completes.

Your completed mobile action sheet
We now have a reusable mobile action sheet pattern: a deliberate trigger, a concise action model, a DOM Studio overlay, a separate destructive path, and an acceptance test that covers the most important modal behavior.
Next, add the pattern to a real list-row or detail-view command and test it against your product’s longest labels and highest-risk actions. When we need editable building blocks for that work, the DOM Studio Action Sheet, responsive dashboard shell, and mobile primitives give us a consistent foundation without locking the app into a one-off implementation.
