Notifications
In-app notification surfaces — a stacked feed panel, a single content card, a dense inbox row, and a corner count badge.
Preview
New comment on your design Unread
2m agoAria mentioned you in “Onboarding revamp”.
Deployment succeeded
1h agov2.4.0 is live across all regions.
Storage almost full
3h agoYou've used 92% of your plan's storage.
<div class="mx-auto w-full max-w-md space-y-3">
<x-ui.notification-card
type="info"
title="New comment on your design"
message="Aria mentioned you in “Onboarding revamp”."
time="2m ago"
avatar-name="Aria Vance"
:unread="true"
:actions="[['label' => 'Reply', 'variant' => 'outline'], ['label' => 'Mute', 'variant' => 'ghost']]"
/>
<x-ui.notification-card
type="success"
title="Deployment succeeded"
message="v2.4.0 is live across all regions."
time="1h ago"
:dismissible="true"
/>
<x-ui.notification-card
type="warning"
title="Storage almost full"
message="You've used 92% of your plan's storage."
time="3h ago"
/>
</div>
Installation
php artisan ui:add notification-card
Registry contract
php artisan ui:add notification-card
writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.
-
resources/views/components/ui/notification-card.blade.php
Use with AI
A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.
# Brok UI: Notification Card (`notification-card`)
A styled single notification with a sender avatar or status glyph, message, timestamp, unread dot and optional action buttons.
Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.
## Install
```bash
php artisan ui:add notification-card
```
## Usage
```blade
<div class="mx-auto w-full max-w-md space-y-3">
<x-ui.notification-card
type="info"
title="New comment on your design"
message="Aria mentioned you in “Onboarding revamp”."
time="2m ago"
avatar-name="Aria Vance"
:unread="true"
:actions="[['label' => 'Reply', 'variant' => 'outline'], ['label' => 'Mute', 'variant' => 'ghost']]"
/>
<x-ui.notification-card
type="success"
title="Deployment succeeded"
message="v2.4.0 is live across all regions."
time="1h ago"
:dismissible="true"
/>
<x-ui.notification-card
type="warning"
title="Storage almost full"
message="You've used 92% of your plan's storage."
time="3h ago"
/>
</div>
```
## Props
- `title` (string, default `New comment on your design`) — Notification headline.
- `message` (string, default `Aria mentioned you in “Onboarding revamp”. Tap to jump straight to the thread.`) — Supporting body text, auto-escaped.
- `time` (string, default `2m ago`) — Relative or absolute timestamp shown at the top-right.
- `type` (string, default `info`) — Tone of the leading status glyph when no avatar is set: info, success, warning, or destructive.
- `avatar` (mixed|null, default `null`) — Avatar image source; shown instead of the status glyph when set.
- `avatarName` (mixed|null, default `null`) — Name used for the avatar's alt text and initials fallback.
- `unread` (bool, default `false`) — Shows an unread dot next to the title and tints the card background.
- `actions` (array, default `[]`) — Array of {label, href, variant} rendered as buttons under the message.
- `dismissible` (bool, default `true`) — Shows a close button; the button is presentational and needs a click handler from the consumer to remove the card.
## Use when
- Use for important messages that should stay visible long enough to read and act on.
- Rendering one styled notification with a sender avatar or status glyph, message, timestamp, and optional action buttons.
- Needing an unread indicator and a dismiss control on a single notification row.
## Avoid when
- Do not downgrade important guidance into transient messaging users can miss.
- Overlaying a count or dot on a trigger icon; use notification-badge instead.
- Listing many notifications together; compose several notification-card instances inside a notification panel.
## Anti-patterns
- Downgrading important outcomes to transient feedback
## Rules
- Use the `<brok:notification-card>` tag (or `<x-ui.notification-card>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.
## Links
- Docs: https://brokui.dev/docs/components/notification-card
- Registry JSON (files, props, contract): https://brokui.dev/r/open/notification-card.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | New comment on your design | Notification headline. |
| message | string | Aria mentioned you in “Onboarding revamp”. Tap t... | Supporting body text, auto-escaped. |
| time | string | 2m ago | Relative or absolute timestamp shown at the top-right. |
| type | string | info | Tone of the leading status glyph when no avatar is set: info, success, warning, or destructive. |
| avatar | mixed | null | null | Avatar image source; shown instead of the status glyph when set. |
| avatarName | mixed | null | null | Name used for the avatar's alt text and initials fallback. |
| unread | bool | false | Shows an unread dot next to the title and tints the card background. |
| actions | array | [] | Array of {label, href, variant} rendered as buttons under the message. |
| dismissible | bool | true | Shows a close button; the button is presentational and needs a click handler from the consumer to remove the card. |
Slots
default— Unused; the component has no visible default slot content.
Data slots
Stable hooks for CSS overrides and browser tests.
Behavior
- Shows the avatar when avatar or avatarName is set; otherwise renders a tone-coloured status glyph based on type.
- The dismiss button is presentational only; wire an @click or wire:click handler via the consuming template to remove the card.
- Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.
Guidance
Keep an important message visible near its context.
Use when
- Use for important messages that should stay visible long enough to read and act on.
- Rendering one styled notification with a sender avatar or status glyph, message, timestamp, and optional action buttons.
- Needing an unread indicator and a dismiss control on a single notification row.
Avoid when
- Do not downgrade important guidance into transient messaging users can miss.
- Overlaying a count or dot on a trigger icon; use notification-badge instead.
- Listing many notifications together; compose several notification-card instances inside a notification panel.
Use instead
- Toast for low-priority confirmation
Anti-patterns
- Downgrading important outcomes to transient feedback
- Anatomy
- Theming hooks
Accessibility
- Keyboard
- native
- Focus
native
- The root carries role="status" so an unread notification is announced when it is added to the page.
- The unread indicator pairs a visible dot with a localized sr-only "Unread" label.
- Semantic HTML and a stable
data-slotattribute for styling and scripting hooks. - Focus-visible rings use the
ringtoken, so keyboard focus is always visible. - Disabled and invalid states are conveyed to assistive tech, not by color alone.
- Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
- Labels go through
__()and layout uses logical properties (ms-*,text-start), so it mirrors underdir="rtl"— flip the preview to RTL to confirm. - Dark mode uses the same semantic tokens under the
darkclass; high contrast follows forced-color system tokens.
Livewire
Livewire can update this component through forwarded wire:* attributes.
Validation
Validation support: native. Keep the error message connected with aria-describedby.
<form wire:submit="save" class="space-y-2">
<brok:notification-card
wire:model="value"
:aria-invalid="$errors->has('value') ? 'true' : 'false'"
aria-describedby="value-error"
/>
@error('value')
<p id="value-error" role="alert">{{ $message }}</p>
@enderror
<brok:button type="submit" wire:loading.attr="disabled">
<span wire:loading.remove>Save</span>
<span wire:loading>Saving…</span>
</brok:button>
</form>
Source
The exact, editable file ui:add writes
into your app. Previews render this same code; there are no preview-only components.
@props([
'title' => 'New comment on your design',
'message' => 'Aria mentioned you in “Onboarding revamp”. Tap to jump straight to the thread.',
'time' => '2m ago',
'type' => 'info',
'avatar' => null,
'avatarName' => null,
'unread' => false,
'actions' => [],
'dismissible' => true,
])
@php
$actions = is_array($actions) ? $actions : [];
// Type → soft icon badge tone + glyph. Unknown types fall back to info.
$types = [
'info' => 'bg-info-soft text-info-text',
'success' => 'bg-success-soft text-success-text',
'warning' => 'bg-warning-soft text-warning-text',
'destructive' => 'bg-destructive-soft text-destructive-text',
];
// Initials for the avatar fallback ("Aria Vance" → "AV"), never the whole name.
$initials = $avatarName
? mb_strtoupper(implode('', array_map(fn ($w) => mb_substr($w, 0, 1), array_slice(preg_split('/\s+/', trim($avatarName)) ?: [], 0, 2))))
: null;
$iconClass = $types[$type] ?? $types['info'];
$glyphs = [
'info' => 'M12 16v-5M12 8h.01',
'success' => 'M8 12l3 3 5-6',
'warning' => 'M12 9v4M12 17h.01',
'destructive' => 'M15 9l-6 6M9 9l6 6',
];
$glyph = $glyphs[$type] ?? $glyphs['info'];
@endphp
{{--
Notification card — one styled notification. Leads with either a sender
avatar or a tone-coloured status glyph, followed by title, message and a
relative timestamp; an unread dot, optional action buttons and a dismiss
control round it out. Message text is auto-escaped.
--}}
<div
data-slot="notification-card"
data-type="{{ $type }}"
@if ($unread) data-unread="true" @endif
role="status"
{{ $attributes->merge(['class' => 'flex gap-3 rounded-md border border-border bg-card p-4 text-foreground shadow-xs data-[unread=true]:bg-accent/40']) }}
>
@if ($avatar || $avatarName)
<x-ui.avatar size="sm" :src="$avatar" :alt="$avatarName ?? ''" :fallback="$initials" class="shrink-0" />
@else
<span class="inline-flex size-8 shrink-0 items-center justify-center rounded-full {{ $iconClass }}" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4">
<circle cx="12" cy="12" r="9" />
<path d="{{ $glyph }}" />
</svg>
</span>
@endif
<div class="min-w-0 flex-1">
<div class="flex items-start gap-2">
<p class="min-w-0 flex-1 text-sm font-medium leading-snug">
{{ $title }}
@if ($unread)
<span class="ms-1 inline-block size-2 -translate-y-px rounded-full bg-ring" aria-hidden="true"></span>
<span class="sr-only">{{ __('Unread') }}</span>
@endif
</p>
@if ($time)
<span class="shrink-0 whitespace-nowrap text-xs text-muted-foreground">{{ $time }}</span>
@endif
</div>
@if ($message)
<p class="mt-1 text-sm text-muted-foreground">{{ $message }}</p>
@endif
@if (count($actions))
<div class="mt-2 flex flex-wrap gap-2">
@foreach ($actions as $action)
<x-ui.button
:href="$action['href'] ?? null"
size="sm"
:variant="$action['variant'] ?? 'outline'"
>{{ $action['label'] ?? __('Open') }}</x-ui.button>
@endforeach
</div>
@endif
</div>
@if ($dismissible)
<button
type="button"
class="-me-1 -mt-1 inline-flex size-7 shrink-0 items-center justify-center self-start rounded-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-[length:var(--ring-width)] focus-visible:ring-ring motion-reduce:transition-none"
aria-label="{{ __('Dismiss notification') }}"
>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="size-4">
<path d="M18 6 6 18M6 6l12 12" />
</svg>
</button>
@endif
</div>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.1.1 - Status
- Stable
- License
-
open - Accessibility reviewed
- No review date recorded
- Last breaking change
- No date recorded
- Deprecation
- Not deprecated
- Contract
-
v6 - Foundation
-
≥ 1.0.0