Message
A neo-brutalist functional message notification system (useMessage). Built with singleton container dynamic mounting on demand and TransitionGroup stacking animations — no component declaration needed in templates. For modal dialog containers, please refer to Dialog. For confirmation / prompt feedback dialogs, please refer to MessageBox.
Demo
四种消息类型
高级配置
Installation
pnpm dlx brutx-vue@latest add messageUsage
Basics
Use the info, success, warning, and error shortcut methods to display different types of messages.
<script setup>
import { useMessage } from 'brutx-ui-vue'
const { info, success, warning, error } = useMessage()
</script>
<template>
<button @click="info('Info', 'This is an informational message')">Info</button>
<button @click="success('Success', 'Operation completed successfully')">Success</button>
<button @click="warning('Warning', 'Please review your input')">Warning</button>
<button @click="error('Error', 'Operation failed, please try again')">Error</button>
</template>Custom Configuration
Use the show method with a full options object to customize duration, closability, and more.
<script setup>
import { useMessage } from 'brutx-ui-vue'
const { show } = useMessage()
function showCustom() {
show({
type: 'warning',
title: 'Session Expiring',
description: 'Your session will expire in 5 minutes. Please save your work.',
duration: 8000,
closable: true,
})
}
function showPersistent() {
show({
type: 'error',
title: 'Network Disconnected',
description: 'Please check your network settings and try again.',
duration: 0,
})
}
</script>
<template>
<button @click="showCustom">Custom Duration (8s)</button>
<button @click="showPersistent">No Auto-close</button>
</template>Manual Close
Every method returns a close function. Call it to manually dismiss the corresponding message.
<script setup>
import { useMessage } from 'brutx-ui-vue'
import { ref } from 'vue'
const { info } = useMessage()
const closeFn = ref(null)
function open() {
closeFn.value = info('Loading', 'Processing your request, please wait...')
}
function close() {
closeFn.value?.()
}
</script>
<template>
<button @click="open">Open Message</button>
<button @click="close">Close Manually</button>
</template>Props
Message is invoked as a function (message.success(options) / useMessage() show(options)); the argument is MessageOptions. Key options:
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'info' | 'success' | 'warning' | 'error' | 'info' | Message type |
title | string | '' | Title text |
description | string | — | Description text |
duration | number | 3000 | Auto-close delay (ms); 0 disables auto-close |
closable | boolean | true | Whether to show the close button |
Data Types
MessageType
type MessageType = 'info' | 'success' | 'warning' | 'error'MessageOptions
interface MessageOptions {
type?: 'info' | 'success' | 'warning' | 'error'
title?: string
description?: string
duration?: number
closable?: boolean
}| Field | Type | Default | Description |
|---|---|---|---|
type | 'info' | 'success' | 'warning' | 'error' | 'info' | Message type |
title | string | '' | Title text |
description | string | — | Description text |
duration | number | 3000 | Auto-close duration in milliseconds; set to 0 to disable auto-close |
closable | boolean | true | Whether to show the close button |
MessageItem
interface MessageItem {
id: string
type: MessageType
title: string
description?: string
duration: number
closable: boolean
}ShowDialogOptions
type RenderableContent = string | Component | VNode | (() => string | Component | VNode | null)
interface ShowDialogOptions {
title?: string
content?: RenderableContent
footer?: RenderableContent
draggable?: boolean
dragHandle?: string | HTMLElement
bounds?: 'parent' | 'viewport' | { top: number; left: number; right: number; bottom: number }
initialPosition?: { x: number; y: number }
resizable?: boolean
minWidth?: number
minHeight?: number
maxWidth?: number
maxHeight?: number
aspectRatio?: number
showCloseButton?: boolean
forceMount?: boolean
fullscreen?: boolean
beforeClose?: ((done: () => void) => void) | (() => boolean | Promise<boolean>)
destroyOnClose?: boolean
zIndex?: number
class?: string
}| Field | Type | Default | Description |
|---|---|---|---|
title | string | — | Dialog title |
content | RenderableContent | — | Dialog content; supports string, component, VNode, or render function |
footer | RenderableContent | — | Footer content |
draggable | boolean | false | Whether the dialog is draggable |
dragHandle | string | HTMLElement | — | Drag handle (CSS selector or element) |
bounds | 'parent' | 'viewport' | object | 'viewport' | Drag boundaries |
initialPosition | { x: number; y: number } | — | Initial position |
resizable | boolean | false | Whether the dialog is resizable |
minWidth | number | — | Minimum width |
minHeight | number | — | Minimum height |
maxWidth | number | — | Maximum width |
maxHeight | number | — | Maximum height |
aspectRatio | number | — | Lock aspect ratio |
showCloseButton | boolean | true | Whether to show the close button |
forceMount | boolean | — | Force mount |
fullscreen | boolean | false | Fullscreen mode |
beforeClose | ((done) => void) | (() => boolean | Promise<boolean>) | — | Close hook (supports callback and Promise mode) |
destroyOnClose | boolean | false | Destroy content after closing |
zIndex | number | — | Custom z-index |
class | string | — | Custom CSS class |
MessageBoxOptions
interface MessageBoxOptions extends ShowDialogOptions {
message?: string
type?: 'info' | 'success' | 'warning' | 'error'
showCancelButton?: boolean
cancelButtonText?: string
confirmButtonText?: string
confirmButtonClass?: string
cancelButtonClass?: string
showInput?: boolean
inputPlaceholder?: string
inputValue?: string
inputPattern?: RegExp
inputErrorMessage?: string
}| Field | Type | Default | Description |
|---|---|---|---|
message | string | — | Prompt message text |
type | 'info' | 'success' | 'warning' | 'error' | — | Message type |
showCancelButton | boolean | false | Whether to show the cancel button |
cancelButtonText | string | 'Cancel' / '取消' | Cancel button text (auto-switches by locale) |
confirmButtonText | string | 'Confirm' / '确定' | Confirm button text (auto-switches by locale) |
confirmButtonClass | string | — | Custom CSS class for the confirm button |
cancelButtonClass | string | — | Custom CSS class for the cancel button |
showInput | boolean | false | Whether to show an input field |
inputPlaceholder | string | — | Input placeholder text |
inputValue | string | '' | Initial input value |
inputPattern | RegExp | — | Input validation regex |
inputErrorMessage | string | 'Invalid format' | Validation error message |
Composables
useMessage
import { useMessage } from 'brutx-ui-vue'
const {
info, // (title: string, description?: string) => () => void
success, // (title: string, description?: string) => () => void
warning, // (title: string, description?: string) => () => void
error, // (title: string, description?: string) => () => void
show, // (options: MessageOptions) => () => void
} = useMessage()| Method | Parameters | Return | Description |
|---|---|---|---|
info | (title: string, description?: string) | () => void | Show an info message; returns a close function |
success | (title: string, description?: string) | () => void | Show a success message; returns a close function |
warning | (title: string, description?: string) | () => void | Show a warning message; returns a close function |
error | (title: string, description?: string) | () => void | Show an error message; returns a close function |
show | (options: MessageOptions) | () => void | Show a custom message; returns a close function |
Key features:
- Singleton pattern: Automatically mounts
MessageContainertobodyon first call — no manual declaration needed - Stacked animations: Multiple messages stack vertically via
TransitionGroupwith smooth reordering - Auto-close: Closes automatically after 3 seconds by default; customize with
duration, set to0to disable - Manual close: Each method returns a
closefunction — call it to dismiss the message immediately - Active message guard & Lazy GC: Equipped with dual component refCount and active message guards; active messages are never killed abruptly on unmount. Triggers a 3000ms lazy GC once all messages clear and refCount reaches 0
- Explicit destruction: Exported
destroyFallback()(or batch cleanup viadestroyBrutxUI()) for test isolation and HMR resets - SSR safe: Uses an internal
isClientguard; no side effects or errors in server-side rendering
useDialog
import { useDialog } from 'brutx-ui-vue'
const {
show, // (options?: ShowDialogOptions) => { close: () => void; promise: Promise<void> }
} = useDialog()| Method | Parameters | Return | Description |
|---|---|---|---|
show | (options?: ShowDialogOptions) | { close, promise } | Open a dialog |
Return values:
| Property | Type | Description |
|---|---|---|
close | () => void | Manually close the dialog |
promise | Promise<void> | Resolves when the dialog is closed |
useMessageBox
import { useMessageBox } from 'brutx-ui-vue'
const {
show, // (options?: MessageBoxOptions) => { close: () => void; promise: Promise<{ value: string } | undefined> }
} = useMessageBox()| Method | Parameters | Return | Description |
|---|---|---|---|
show | (options?: MessageBoxOptions) | { close, promise } | Open a confirm/input prompt |
Return values:
| Property | Type | Description |
|---|---|---|
close | () => void | Manually close the message box |
promise | Promise<MessageBoxResult> | Always resolves { action, value? }: action='confirm' on confirm (value is the input when showInput); action='cancel' on cancel/close button/ESC/overlay; action='destroy' on manual destroy |
Accessibility
- Keyboard: Dialogs support
Escapeto close - ARIA Attributes: Messages use
role="status"andaria-live="polite"to notify screen readers; the close button includes a localizedaria-labelfor screen reader support - Focus Management:
useDialoganduseMessageBoxare built on reka-ui'sDialogRoot, trapping focus on open and restoring it on close - Reduced Motion: Respects the
prefers-reduced-motionsystem setting and automatically simplifies transition animations
FAQ
Q: What is the difference between useMessage and useToast?
A: useMessage is a lightweight top-center notification, ideal for brief operation feedback. useToast offers richer features including configurable positions, stacking options, Promise tracking, and hover-to-pause — better suited for complex notification scenarios.
Q: Will message notifications cause errors in SSR?
A: No. useMessage uses an internal isClient guard, so calling it in a server-side rendering environment produces no side effects and no errors.
Q: How do I perform async validation before closing a dialog?
A: Use the beforeClose hook, which supports both callback and Promise modes:
<script setup>
import { useDialog } from 'brutx-ui-vue'
const { show } = useDialog()
function openWithValidation() {
show({
title: 'Edit Profile',
content: 'Form content...',
beforeClose: async () => {
const isValid = await validateForm()
return isValid
},
})
}
</script>Q: When does the useMessageBox promise reject?
A: It never rejects. The promise always resolves with MessageBoxResult: confirm button → { action: 'confirm' } (value included with showInput); cancel button / ESC / overlay / close button → { action: 'cancel' }; manual destroy() → { action: 'destroy' }. Check result.action === 'confirm' (the old .catch() branch is deprecated).