BuMessage
Bulma’s .message with a dismissible header and a headerless body-only variant.
Reference: Message on bulma.io↗︎ — classes and visual variants. This page is the JavaScript.
Usage
BuMessage is article.message and owns visibility through v-model, default true. Compose BuMessageHeader and BuMessageBody inside it. Dismiss is opt-in: compose BuMessageDelete inside the header. A header without Delete is a title-only bar. Omitting the header is the documented body-only variant.
Anatomy
<script setup lang="ts">
import { BuMessage, BuMessageBody, BuMessageDelete, BuMessageHeader } from '@paper/bulma'
</script>
<template>
<BuMessage>
<BuMessageHeader>
<BuMessageDelete />
</BuMessageHeader>
<BuMessageBody />
</BuMessage>
</template>Composed on v0
BuMessage wraps v0’s Presence the same way BuNotification does: v-model drives present/leaving/unmounted, data-state lands on article.message, and a dismiss unmounts the article on the next tick.
The rest is package context, not a v0 compound. BuMessage provides bulma:message with a close() that writes false through the model. BuMessageDelete is the only consumer — it renders button.delete and calls close() on click. BuMessageHeader and BuMessageBody inject nothing; they are classed divs.
Injection is optional. A Delete rendered outside BuMessage still emits the button, warns once in dev, and the click is inert. Parts backed by a v0 context throw instead; this family does not.
Presence does not supply a header, a body, or a close control. Those are Bulma’s regions, expressed as parts, which is why a message with no BuMessageHeader is still a valid message — it is the body-only fixture, not a half-composed one. A header with no BuMessageDelete is a valid title-only header.
The markup you know
The Bulma tab is the markup published on bulma.io↗︎, captured verbatim in the conformance fixture. The Vue tab is the component that renders it. The conformance suite diffs the two on every test run — type="button" on the delete control is the tolerated difference.
<article class="message">
<div class="message-header">
<p>Hello World</p>
<button class="delete" aria-label="delete"></button>
</div>
<div class="message-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<strong>Pellentesque risus mi</strong>, tempus quis placerat ut, porta nec
nulla. Vestibulum rhoncus ac ex sit amet fringilla. Nullam gravida purus
diam, et dictum <a>felis venenatis</a> efficitur.
</div>
</article><template>
<BuMessage>
<BuMessageHeader>
<p>Hello World</p>
<BuMessageDelete />
</BuMessageHeader>
<BuMessageBody>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<strong>Pellentesque risus mi</strong>, tempus quis placerat ut, porta nec
nulla. Vestibulum rhoncus ac ex sit amet fringilla. Nullam gravida purus
diam, et dictum <a>felis venenatis</a> efficitur.
</BuMessageBody>
</BuMessage>
</template>You write no close handler. Composing BuMessageDelete inside the header is what opts the message into being dismissible.
Examples
Props
BuMessage renders article.message and owns visibility. The regions are parts.
| Prop | Type | Default | Description |
|---|---|---|---|
v-model | boolean | true | Visibility. false unmounts the message |
color | 'primary' | 'link' | 'info' | 'success' | 'warning' | 'danger' | — | is-{color} |
size | 'small' | 'normal' | 'medium' | 'large' | — | is-{size} |
| Part | Renders | Notes |
|---|---|---|
BuMessageHeader | div.message-header | Slot only; compose optional BuMessageDelete |
BuMessageDelete | button.delete | Calls close() on bulma:message |
BuMessageBody | div.message-body | Pure markup; the headerless variant is a message with no header |
The header’s default slot is the title. Bulma wraps its own in a <p>; the part does not wrap for you.
Accessibility
BuMessageDelete carries aria-label="delete" and type="button", matching the fixture. Dismiss is that click. There is no Escape handler, and nothing moves focus when the message appears or leaves.
A BuMessageDelete rendered outside BuMessage still emits the button. In development it warns once that bulma:message was missing; the click then does nothing. Nest the part, or you get a button that looks like a close control and isn’t one.
The root is an article with no live-region role. It will not announce itself. Put the severity in the header text; color is decoration.