- Controls the visual appearance of the card — colors, icon, and button state. Six available themes:
- Info – Informational (default)
- Validated – Success / confirmation
- Invalid – Error / failure
- Warning – Caution / alert
- Generic – Neutral, low-contrast
- Locked – Restricted, buttons disabled
MessageCard
Organism
Message Card is designed for short, contextual messages, alerts, and status information within the interface.
Unlike toasts or snackbars, Message Card does not appear dynamically or disappear after a timeout. It is statically nested within the interface layout — always visible in context as part of the page content.
Common use cases include: form validation feedback, success confirmations after saving, permission or access warnings, system maintenance notices, and onboarding tips.
It supports multiple action types (buttons, links, or none), a collapsible state, and an optional custom content area for flexible composition.
The width of Message Card is defined by its container. Its height adapts to the content and applied padding.
Keep messages concise — avoid excessively long text. This component is not intended for detailed explanations or multi-paragraph content. If the message requires more space, consider using a dedicated content component instead.
Playground
<
MessageCard
status
=
"info"
text
=
"Supporting text for the message card. longer text so it wrappes down eventually into the third row also."
dismissible
collapsible
open
actions
=
"[
{
"text": "Abbrechen",
"icon": "ai",
"secondary": true
},
{
"type": "button",
"text": "Fortfahren",
"icon": "chevron_right",
"trailingIcon": true
}
]"
title
=
"Message Card Title"
v-model
=
"true"
/>
ModelValues
For more information on ModelValues please have a look to the Vue's Data Binding section.
ts
const visible = defineModel<boolean>({ required: false, default: true });Properties
ts
export type MessageCardStatus = HelpTextCategory | 'generic';
type MessageCardActionHandler = {
onClick?: () => boolean | Promise<boolean> | void;
};
/** Default action: omit `type` (or set `type: 'button'`) → AppButton props. */
export type MessageCardButtonAction =
& Omit<AppButtonProps, 'size'>
& MessageCardActionHandler
& {
type?: 'button';
};
/**
* Link action: `type: 'link'` required.
* Link's own visual `type` (primary/secondary/tertiary) is exposed as `linkType`
* to avoid colliding with the action discriminant.
*/
export type MessageCardLinkAction =
& Omit<LinkProps, 'type' | 'size'>
& MessageCardActionHandler
& {
type: 'link';
linkType?: LinkType;
};
export type MessageCardAction = MessageCardButtonAction | MessageCardLinkAction;
export interface MessageCardProps {
status?: MessageCardStatus;
text?: string;
title?: string;
disabled?: boolean;
dismissible?: boolean;
collapsible?: boolean;
open?: boolean;
ultraWide?: boolean;
actions?: MessageCardAction[];
}Event Emits
ts
const emits = defineEmits<{
close: [];
}>();Slots
ts
const slots = defineSlots<{
actions?: () => VNode | VNode[];
default?: () => VNode | VNode[];
}>();Anatomy
- Container - The outer wrapper of the card. Defines the overall layout, background color, border (outline), and internal padding. Appearance changes based on the active Status theme.
- Icon - A status icon displayed at the start of the message. The icon automatically changes based on the Status theme: Info → info icon, Validated → check icon, Invalid → error icon, Warning → warning icon. Its color also changes accordingly.
- Title - An optional heading displayed above the message text. Visible only in the "Title + Text" content mode. Useful for giving the message a clear, scannable label.
- Text Container - The primary message area containing the icon and text content. Displayed in a horizontal layout.
- Slot - An optional content area that replaces the default message text with custom content. Enabled via the Slot option.
- Action Area - An optional area at the bottom of the card containing action buttons or links. Controlled by the Action Type option (Buttons, Links or None).
- Controls - The top-right area containing the expand/collapse chevron toggle and the close (dismiss) button. Uses the Icon Button component with colors locally adjusted to match each Message Card type.
States
Variants
Action Type
- Determines the type of actions displayed in the card's action area. Buttons and Links each support one or two actions.
- Buttons – Displays primary and secondary action buttons at the bottom of the card.
- Links – Displays text links as the card's actions.
- None – No action area is shown.
Dismissable
- Controls whether the card can be dismissed by the user.
- Yes – A close button (×) is visible in the Controls area. The dismiss action is handled by the consuming application.
- No – The close button is hidden. The card stays visible until removed programmatically.
- This property is independent of Collapsible — both can be enabled at the same time.
Collapsible
- Controls whether the card can be expanded and collapsed via the chevron icon.
- Yes – The chevron toggle is visible. Users can expand or collapse the card content.
- No – The chevron is hidden. The card content is always fully visible.
- This property is independent of Dismissable — both can be enabled at the same time.
Open
- Controls the default expanded/collapsed state. Only available when Collapsible is Yes.
- Yes – Card is fully expanded, showing all content and actions.
- No – Card is collapsed to a single line with truncated text (…). Action area and content area are hidden. The closed state always maintains the same fixed height regardless of the content type.
Ultra Wide
- Controls the width behavior of the card.
- Yes – Most commonly used inside a wide modal, but ultimately it's the designer's decision where to use each option — this is project-specific.
- No – The card uses its default, compact width. Again, the width depends on the local context and is ultimately the designer's decision.
- Note: The Ultra Wide variant does not support collapsible, dismissable, or link actions. Since this variant is typically used inside a modal, additional controls would be redundant — the modal itself already handles dismissal and context. If links are set, the component falls back to buttons. Only buttons are available, placed on the right side — the layout changes accordingly.
Content
- Controls the content area within the card.
- Title + Text – Displays a title above the message text, similar to a card with a heading. When closed, the body text is hidden and only the title remains visible. If the title exceeds the container width, it is also truncated with an ellipsis.
- Text Only – The default text style is used for the message. When closed, the text is truncated to a single line with an ellipsis.
- Slot – A slot replaces the default message text. The designer decides what goes inside the slot — it can hold any custom content. When closed, the first 14px of the slot content is visible vertically — the rest is clipped.
Developer notes
- Visibility is controlled with optional
v-model(boolean, defaulttrue). Dismiss sets it tofalseand emitsclose. actionsis a discriminated list: omittype(ortype: 'button') for AppButton props; usetype: 'link'for Link (visual link style vialinkType).- Content modes map to props/slots:
title+text→ Title + Text;textonly → Text Only; default slot → Slot. When closed with a title, body text is hidden and the title truncates; Text Only truncates to one line; Slot clips to the first 14px vertically. - Ultra Wide hides collapsible/dismissible controls; action layout moves beside the message.
vue
<script setup>
import { reactive, ref } from 'vue';
import {
MessageCard,
type MessageCardAction,
} from '@pohlcon/design-system';
const visible = ref(true);
const actions = reactive<MessageCardAction[]>([
{
// defaults to button (AppButtonProps) when `type` is omitted
text: 'Abbrechen',
icon: 'ai',
secondary: true,
onClick: () => true,
},
{
type: 'button',
text: 'Fortfahren',
icon: 'chevron_right',
trailingIcon: true,
onClick: () => true,
},
]);
</script>
<template>
<MessageCard
v-model="visible"
status="info"
title="Message Card Title"
text="Supporting text for the message card."
:actions="actions"
@close="visible = false"
/>
</template>