StatusBanner
Reusable status banner component.
Usage
Components are auto-discovered. Use the component directly in any .wrn view:
<StatusBanner
type="info"
title="title"
description="description"
actionLabel="actionLabel"
actionHref="actionHref"
/>Legacy mount name: data-component="StatusBanner".
Props and attributes
| Prop | Type | Requirement | Default |
|---|---|---|---|
class | string | Optional | "" |
type | string | Optional | "info" |
title | string | Optional | "" |
description | string | Optional | "" |
actionLabel | string | Optional | "" |
actionHref | string | Optional | "" |
dismissible | boolean | Optional | true |
compact | boolean | Optional | false |
details | string | Optional | [] |
Slots
This component does not declare a slot.
Events
click
Source contract
Installed source: components/StatusBanner.wrn
component StatusBanner {
props {
class: string = ""
type = "info"
title = ""
description = ""
actionLabel = ""
actionHref = ""
dismissible = true
compact = false
details = []
}
state visible = true
view {
<aside
role="{type === 'error' ? 'alert' : 'status'}"
aria-live="{type === 'error' ? 'assertive' : 'polite'}"
class="relative overflow-hidden {class}"
class:hidden="!visible"
>
<div
class=" relative overflow-hidden rounded-2xl {compact ? 'px-4 py-3' : 'px-5 py-4 sm:px-6'} {type === 'success' ? 'bg-emerald-50 text-emerald-950 ring-1 ring-inset ring-emerald-200 dark:bg-emerald-500/10 dark:text-emerald-100 dark:ring-emerald-500/20' : type === 'warning' ? 'bg-amber-50 text-amber-950 ring-1 ring-inset ring-amber-200 dark:bg-amber-500/10 dark:text-amber-100 dark:ring-amber-500/20' : type === 'error' ? 'bg-rose-50 text-rose-950 ring-1 ring-inset ring-rose-200 dark:bg-rose-500/10 dark:text-rose-100 dark:ring-rose-500/20' : 'bg-indigo-50 text-indigo-950 ring-1 ring-inset ring-indigo-200 dark:bg-indigo-500/10 dark:text-indigo-100 dark:ring-indigo-500/20' } "
>
<!-- Decorative glow -->
<div aria-hidden="true" class=" pointer-events-none absolute -right-16 -top-20 h-40 w-40 rounded-full blur-3xl {type === 'success' ? 'bg-emerald-300/30 dark:bg-emerald-500/10' : type === 'warning' ? 'bg-amber-300/30 dark:bg-amber-500/10' : type === 'error' ? 'bg-rose-300/30 dark:bg-rose-500/10' : 'bg-indigo-300/30 dark:bg-indigo-500/10' } " >
</div>
<div
class="relative flex gap-4"
class:items-center="compact"
class:items-start="!compact"
>
<!-- Icon -->
<span
class=" grid shrink-0 place-items-center rounded-xl {compact ? 'h-9 w-9' : 'h-10 w-10'} {type === 'success' ? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300' : type === 'warning' ? 'bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300' : type === 'error' ? 'bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300' : 'bg-indigo-100 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300' } "
>
<span class=" h-5 w-5 {type === 'success' ? 'icon-[lucide--circle-check]' : type === 'warning' ? 'icon-[lucide--triangle-alert]' : type === 'error' ? 'icon-[lucide--circle-x]' : 'icon-[lucide--info]' } " aria-hidden="true" >
</span>
</span>
<!-- Content -->
<div class="min-w-0 flex-1">
<div
class="flex flex-col gap-3 sm:flex-row sm:justify-between"
class:sm:items-center="compact"
class:sm:items-start="!compact"
>
<div class="min-w-0">
<h2
class="font-bold"
class:text-sm="compact"
class:text-base="!compact"
class:hidden="title === ''"
>
{title}
</h2>
<p
class="text-sm leading-6 opacity-80"
class:mt-1="title !== ''"
class:hidden="description === ''"
>
{description}
</p>
</div>
<!-- Actions -->
<div class="flex shrink-0 items-center gap-2">
<a
href="{actionHref}"
class=" h-9 items-center justify-center gap-1.5 rounded-lg px-3 text-xs font-bold transition {type === 'success' ? 'bg-emerald-600 text-white hover:bg-emerald-500' : type === 'warning' ? 'bg-amber-600 text-white hover:bg-amber-500' : type === 'error' ? 'bg-rose-600 text-white hover:bg-rose-500' : 'bg-indigo-600 text-white hover:bg-indigo-500' } "
class:hidden="actionLabel === ''"
class:inline-flex="actionLabel !== ''"
>
{actionLabel}
<span class="icon-[lucide--arrow-up-right] h-3.5 w-3.5" aria-hidden="true" >
</span>
</a>
<button
type="button"
@click="visible = false"
aria-label="Dismiss notice"
class="grid h-9 w-9 place-items-center rounded-lg opacity-60 transition hover:bg-black/5 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-current dark:hover:bg-white/10"
class:hidden="!dismissible"
>
<span class="icon-[lucide--x] h-4 w-4" aria-hidden="true" >
</span>
</button>
</div>
</div>
<!-- Dynamic details -->
<div
class="mt-4 flex flex-wrap gap-x-5 gap-y-2 border-t pt-4 text-xs font-medium"
class:hidden="compact || details.length === 0"
class:border-emerald-200="type === 'success'"
class:border-amber-200="type === 'warning'"
class:border-rose-200="type === 'error'"
class:border-indigo-200="type === 'info'"
class:dark:border-emerald-500/20="type === 'success'"
class:dark:border-amber-500/20="type === 'warning'"
class:dark:border-rose-500/20="type === 'error'"
class:dark:border-indigo-500/20="type === 'info'"
>
{#each details.slice(0, 4) as detail}
<span class="inline-flex items-center gap-2 opacity-80">
<span class="{detail.iconClass} h-3.5 w-3.5" aria-hidden="true" >
</span>
{detail.label}
</span>
{/each}
</div>
</div>
</div>
</div>
</aside>
}
}