Skip to content
Brok UI

Loading…

No results

Notifications

Open source

In-app notification surfaces — a stacked feed panel, a single content card, a dense inbox row, and a corner count badge.

Version
v1.1.1
Stability
stable
License
MIT
Related
Notification Panel
Notification Badge

Notification Card — A styled single notification with a sender avatar or status glyph, message, timestamp, unread dot and optional action buttons.

Preview

AV Aria Vance

New comment on your design Unread

2m ago

Aria mentioned you in “Onboarding revamp”.

Deployment succeeded

1h ago

v2.4.0 is live across all regions.

Storage almost full

3h ago

You've used 92% of your plan's storage.

previews.components.notification-card.default.blade.php 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>

Installation

terminal
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.

  • blade resources/views/components/ui/notification-card.blade.php
Registry dependencies
avatar button
Packages
composer: jml/brok:^0.2

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.

notification-card.md
# 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

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
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.

notification-card

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

Persistent message and notification

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
root
Theming hooks
notification-card

Accessibility

WCAG 2.2 AA Keyboard focus-visible RTL-ready Localized labels Dark mode
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-slot attribute for styling and scripting hooks.
  • Focus-visible rings use the ring token, 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 under dir="rtl" — flip the preview to RTL to confirm.
  • Dark mode uses the same semantic tokens under the dark class; high contrast follows forced-color system tokens.

Livewire

Safe

Livewire can update this component through forwarded wire:* attributes.

Validation

Validation support: native. Keep the error message connected with aria-describedby.

livewire-form.blade.php Blade
<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.

resources/views/components/ui/notification-card.blade.php Blade
@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