Skip to content

MessageBox

A set of modal boxes simulating system message box.

NameCategoryDescriptionTypeDefault
type? StyleMessage type'success' | 'warning' | 'info' | 'danger' | 'error'
cancelButtonType? StyleCancel button typeButtonType
confirmButtonType? StyleConfirm button typeButtonType'primary'
center? StyleWhether to center layoutbooleanfalse
inputType? StyleInput type'text' | 'textarea' | 'password' | 'number''text'
customClass? StyleCustom class name applied to dialog rootstring
customStyle? StyleCustom inline styles applied to dialog rootCSSProperties
width? StyleCustom dialog width (number = px, or CSS string)string | number420
overlayClass? StyleCustom class for the overlay backdropstring | string[] | Record<string, boolean>
showClose? BehaviorWhether to show close buttonbooleantrue
showCancelButton? BehaviorWhether to show cancel buttonbooleanfalse
showConfirmButton? BehaviorWhether to show confirm buttonbooleantrue
lockScroll? BehaviorWhether to lock scrollbooleantrue
closeOnClickModal? BehaviorWhether to close on modal clickbooleantrue
showInput? BehaviorWhether to show inputbooleanfalse
callback? BehaviorCallback after closing(action: MessageBoxAction | { value: string; action: MessageBoxAction }) => void
beforeClose? BehaviorCallback before closing; call done to close. If a Promise is returned, the button automatically shows a loading spinner(action: MessageBoxAction, instance: MessageBoxOptions, done: () => void) => void | Promise<void>
closeOnPressEscape? BehaviorWhether to close on Escape key pressbooleantrue
closeOnHashChange? BehaviorWhether to close on URL hash changebooleantrue
inputSchema? BehaviorZod validation schema for prompt inputZodType
distinguishCancelAndClose? BehaviorWhether close button fires "close" instead of "cancel"booleantrue
draggable? BehaviorWhether the dialog is draggable by its headerbooleanfalse
title? ContentTitlestring
message? ContentMessage contentstring | VNode
cancelButtonText? ContentCancel button textstring'No'
confirmButtonText? ContentConfirm button textstring'Yes'
inputPlaceholder? ContentInput placeholderstring
inputValue? ContentInput initial valuestring
inputErrorMessage? ContentCustom error message when input validation failsstring
footer? ContentCustom footer VNode or render function replacing default buttonsVNode | (() => VNode)
PxMessageBox? MethodOpen message box(options: MessageBoxOptions) => Promise<MessageBoxData>
PxMessageBox.alert? MethodOpen alert box(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.confirm? MethodOpen confirm box(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.prompt? MethodOpen prompt box(message, title, options?) => Promise<MessageBoxData>
PxMessageBox.close? MethodClose current box() => void

Alert

Used to alert users, only has a confirm button.

<template>
  <px-button @click="showAlert">Show Alert</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showAlert = () => {
  PxMessageBox.alert('This is an alert message', 'Alert').catch(() => {});
};
</script>

Confirm

Used to ask users to confirm an operation, has confirm and cancel buttons.

<template>
  <px-button @click="showConfirm">Show Confirm</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showConfirm = async () => {
  try {
    await PxMessageBox.confirm('Are you sure to delete this item?', 'Confirm');
    PxMessage.success('Deleted successfully');
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

Prompt

Used to prompt users to input content.

<template>
  <px-button @click="showPrompt">Show Prompt</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showPrompt = async () => {
  try {
    const { value } = await PxMessageBox.prompt('Please input your name', 'Prompt');
    PxMessage.success(`Your name is: ${value}`);
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

Custom Content

Message box content can be customized.

<template>
  <px-button @click="showCustom">Custom MessageBox</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showCustom = async () => {
  try {
    await PxMessageBox({
      title: 'Warning',
      message: 'This action will permanently delete the file. Continue?',
      type: 'warning',
      showCancelButton: true,
      confirmButtonText: 'Yes, delete it',
      cancelButtonText: 'No, cancel',
    });
    PxMessage.success('Deleted!');
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

Center Layout

Use center to align the title and footer to the center.

<template>
  <px-button @click="showCenter">Center Layout</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showCenter = () => {
  PxMessageBox({
    title: 'Warning',
    message: 'This will center the title and footer.',
    type: 'warning',
    center: true,
    showCancelButton: true,
  }).catch(() => {});
};
</script>

BeforeClose Callback

Use beforeClose to intercept the close action. The callback receives the action, the instance, and a done function — call done() to actually close the dialog. If beforeClose returns a Promise, the clicked button automatically shows a loading state until the Promise resolves.

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showCallbackStyle">Callback Style</px-button>
    <px-button @click="showAsyncStyle">Async / Promise Style</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const showCallbackStyle = () => {
  PxMessageBox({
    title: 'Confirm',
    message: 'Are you sure? The dialog will close after 1 second.',
    showCancelButton: true,
    beforeClose: (action, _instance, done) => {
      if (action === 'confirm') {
        setTimeout(() => {
          done();
          PxMessage.success('Confirmed after delay');
        }, 1000);
      } else {
        done();
      }
    },
  });
};

const showAsyncStyle = () => {
  PxMessageBox({
    title: 'Async Confirm',
    message: 'The confirm button will show a loading spinner for 1.5 seconds.',
    showCancelButton: true,
    beforeClose: (action, _instance, done) => {
      if (action === 'confirm') {
        return new Promise<void>((resolve) => {
          setTimeout(() => {
            done();
            PxMessage.success('Async operation completed');
            resolve();
          }, 1500);
        });
      }
      done();
    },
  });
};
</script>

Type-Colored Borders

Setting type to 'info', 'success', 'warning', or 'danger' colors the border, shadow, and divider to match the theme.

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button type="info" @click="showType('info')">Info</px-button>
    <px-button type="success" @click="showType('success')">Success</px-button>
    <px-button type="warning" @click="showType('warning')">Warning</px-button>
    <px-button type="danger" @click="showType('danger')">Danger</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showType = (type: 'info' | 'success' | 'warning' | 'danger') => {
  PxMessageBox({
    title: `${type.charAt(0).toUpperCase() + type.slice(1)} Type`,
    message: `This message box uses the "${type}" type, which colors the border, shadow, and divider.`,
    type,
    showCancelButton: true,
  }).catch(() => {});
};
</script>

Custom Appearance

Use customClass, customStyle, and width to customize the dialog appearance. The width prop accepts a number (pixels) or a CSS string value.

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showCustomClass">Custom Class</px-button>
    <px-button @click="showCustomStyle">Custom Style</px-button>
    <px-button @click="showWidth">Custom Width</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showCustomClass = () => {
  PxMessageBox.alert('This dialog has a custom CSS class applied.', 'Custom Class', {
    customClass: 'my-custom-msgbox',
  }).catch(() => {});
};

const showCustomStyle = () => {
  PxMessageBox.alert('This dialog has custom inline styles.', 'Custom Style', {
    customStyle: {
      '--px-message-box-bg': '#f0f9eb',
      '--px-message-box-border-color': '#67c23a',
    } as any,
  }).catch(() => {});
};

const showWidth = () => {
  PxMessageBox.alert('This dialog is 600px wide.', 'Custom Width (number)', { width: 600 }).catch(
    () => {},
  );
};
</script>

<style>
.my-custom-msgbox {
  --px-message-box-bg: #fdf6ec;
  --px-message-box-border-color: #e6a23c;
}
</style>

Close Controls

Use closeOnPressEscape and closeOnHashChange to control how the dialog can be closed. Both default to true.

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="showNoEscape">Disable ESC Close</px-button>
    <px-button @click="showNoHashChange">Disable Hash Close</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showNoEscape = () => {
  PxMessageBox({
    title: 'No ESC Close',
    message: 'Pressing Escape will NOT close this dialog. Use the buttons instead.',
    showCancelButton: true,
    closeOnPressEscape: false,
  }).catch(() => {});
};

const showNoHashChange = () => {
  PxMessageBox({
    title: 'No Hash Close',
    message: 'Changing the URL hash will NOT close this dialog.',
    showCancelButton: true,
    closeOnHashChange: false,
  }).catch(() => {});
};
</script>

Input Validation

Use inputSchema with a Zod schema to validate prompt input before allowing confirmation. Set inputErrorMessage to customize the error text shown below the input when validation fails.

<template>
  <px-button @click="showValidation">Email Validation</px-button>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';
import { z } from 'zod';

const showValidation = async () => {
  try {
    const { value } = await PxMessageBox.prompt(
      'Please enter your email address',
      'Email Validation',
      {
        inputPlaceholder: 'user@example.com',
        inputSchema: z.string().email(),
        inputErrorMessage: 'Please enter a valid email address',
      },
    );
    PxMessage.success(`Email submitted: ${value}`);
  } catch {
    PxMessage.info('Cancelled');
  }
};
</script>

Distinguish Cancel and Close

When distinguishCancelAndClose is true (default), clicking the close button rejects with 'close', while clicking the cancel button rejects with 'cancel'. Set it to false to make both fire 'cancel'.

<template>
  <div style="display: flex; gap: 8px; flex-wrap: wrap">
    <px-button @click="show(true)">Distinguish (default)</px-button>
    <px-button @click="show(false)">Not Distinguished</px-button>
  </div>
</template>

<script setup lang="ts">
import { PxMessage, PxMessageBox } from 'sakana-element';

const show = async (distinguish: boolean) => {
  try {
    await PxMessageBox({
      title: distinguish ? 'Distinguish Close' : 'Not Distinguished',
      message: distinguish
        ? 'Close button fires "close", cancel button fires "cancel".'
        : 'Both close button and cancel button fire "cancel".',
      showCancelButton: true,
      distinguishCancelAndClose: distinguish,
    });
    PxMessage.success('Action: confirm');
  } catch (action) {
    PxMessage.info(`Action: ${action}`);
  }
};
</script>

Draggable

Set draggable to true to allow the user to drag the dialog by its header. The dialog is constrained to the viewport.

<template>
  <px-button @click="showDraggable">Draggable MessageBox</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';

const showDraggable = () => {
  PxMessageBox({
    title: 'Draggable',
    message: 'Drag the header to move this dialog around.',
    showCancelButton: true,
    draggable: true,
  }).catch(() => {});
};
</script>

Use the footer option to provide a VNode or render function that replaces the default cancel/confirm buttons with custom content.

<template>
  <px-button @click="showCustomFooter">Custom Footer</px-button>
</template>

<script setup lang="ts">
import { PxMessageBox } from 'sakana-element';
import { h } from 'vue';

const showCustomFooter = () => {
  PxMessageBox({
    title: 'Custom Footer',
    message: 'This dialog replaces the default buttons with a custom footer.',
    footer: () =>
      h('div', { style: 'text-align: center; padding: 8px 0' }, [
        h(
          'a',
          {
            href: '#',
            style: 'color: var(--px-color-primary); cursor: pointer',
            onClick: (e: Event) => {
              e.preventDefault();
              PxMessageBox.close();
            },
          },
          'I have read and agree to the terms',
        ),
      ]),
  }).catch(() => {});
};
</script>