Guide
React, Vue, Svelte and the rest
A dialog is a question, not a component tree, so the API is the same everywhere: call it, await the answer. There is no provider to mount and no context to thread through.
React
import { confirmDanger } from '@devix-labs/confirm-dialog/react';
import '@devix-labs/confirm-dialog/styles.css';
async function onDelete(invoice) {
if (await confirmDanger(`Delete invoice ${invoice.number}?`)) {
await api.delete(invoice.id);
}
}
Or, if a hook reads better in your codebase:
import { useDialogs } from '@devix-labs/confirm-dialog/react';
const { confirm, prompt } = useDialogs();
Both are the same functions — which means a route guard, a store or an interceptor can call them too:
router.beforeEach(async (to, from) => (form.dirty ? confirm('Leave without saving?') : true));
Vue
<script setup>
import { confirm } from '@devix-labs/confirm-dialog/vue';
const remove = async (id) => {
if (await confirm('Remove this row?')) items.value = items.value.filter((item) => item.id !== id);
};
</script>
Svelte
<script>
import { confirmDanger } from '@devix-labs/confirm-dialog/svelte';
</script>
<button on:click={async () => (await confirmDanger('Delete?')) && remove()}>Delete</button>
Laravel and Livewire
<button
x-data
x-on:click.prevent="if (await window.dx.confirm('Delete this invoice?')) $wire.delete({{ $invoice->id }})"
>Delete</button>
<script type="module">
import * as dx from 'https://devix.pk/cdn/oss/confirm-dialog@1.0.0/index.js';
window.dx = dx;
</script>
Because it returns a promise, await inside an Alpine handler or a Livewire action is all the wiring
there is.
Replacing window.confirm
import { confirm } from '@devix-labs/confirm-dialog';
// A form that used onsubmit="return confirm('Sure?')"
form.addEventListener('submit', async (event) => {
if (form.dataset.confirmed) return;
event.preventDefault();
if (await confirm(form.dataset.confirm ?? 'Are you sure?')) {
form.dataset.confirmed = '1';
form.requestSubmit();
}
});
Updated 15 Sep 2026