Skip to content
Velocity X Docs
← All components

Inline Alert — 4 Severities

Free · MIT

Static inline banner covering info, success, warning, and error severities with the correct assertive/polite ARIA role per severity.

Category
Core UI
Framework
astro
Version
1.0.0
Peer deps
none

Install

bash
velocityx add inline-alert

Free and MIT licensed — no account needed. The file lands under src/components/velocity/inline-alert/ by default (override with --dest), and it's yours to edit from the moment it's written.

Demo

View the live demo on the showcase site ↗

Source

Pulled live from the registry — this is the exact file velocityx add inline-alert writes into your project right now.

components/velocity/inline-alert/InlineAlert.astro

astro
---
//    VELOCITY COMPONENT · theming
// 
//    Colours here are Tailwind `primary-*` / `accent-*`, which resolve through
//    the Velocity preset. Out of the box they are a neutral indigo — NOT the
//    Aidxn brand — so this drops into your project without dragging our look in.
// 
//    ⚡ NOT USING VELOCITY? Run this once, in your project root:
// 
//          velocityx theme
// 
//    It writes velocity-preset.cjs + velocity-theme.css. Add the preset to your
//    tailwind.config, import the css, then set your whole brand in ONE place:
// 
//          :root {
//            --vx-brand: custom;
//            --vx-primary-600: 220 38 38;   <- your action colour
//            --vx-primary-700: 185 28 28;
//          }
// 
//    ⚠️  Raw RGB channels, space separated — NOT hex. `#DC2626` here silently
//        breaks every /opacity variant in the library (bg-primary-600/20 etc).
// 
//    Prefer not to install anything? Find-and-replace `primary-` with your own
//    scale name. Nothing else in this file depends on Velocity.
/**
 * InlineAlert — static banner for info/success/warning/error severities.
 * Renders as role="alert" for error/warning (assertive) and role="status"
 * for info/success (polite), so screen readers announce it appropriately
 * without the page author having to think about it.
 *
 * Usage:
 *   <InlineAlert severity="warning" title="Check your details">
 *     Your card expires this month — update it to avoid a lapse.
 *   </InlineAlert>
 */
export interface Props {
  severity?: 'info' | 'success' | 'warning' | 'error';
  title?: string;
  dismissible?: boolean;
}
const { severity = 'info', title, dismissible = false } = Astro.props;

const VARIANTS = {
  info: {
    label: 'Info',
    box: 'border-primary-500/25 dark:border-primary-300/20 bg-primary-50 dark:bg-primary-500/10',
    icon: 'text-primary-600 dark:text-primary-300',
    title: 'text-primary-900 dark:text-primary-100',
    role: 'status',
    path: 'M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z',
  },
  success: {
    label: 'Success',
    box: 'border-green-500/25 dark:border-green-400/20 bg-green-50 dark:bg-green-500/10',
    icon: 'text-green-600 dark:text-green-400',
    title: 'text-green-900 dark:text-green-100',
    role: 'status',
    path: 'M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
  },
  warning: {
    label: 'Warning',
    box: 'border-orange-500/30 dark:border-orange-400/25 bg-orange-50 dark:bg-orange-500/10',
    icon: 'text-orange-600 dark:text-orange-400',
    title: 'text-orange-900 dark:text-orange-100',
    role: 'alert',
    path: 'M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z',
  },
  error: {
    label: 'Error',
    box: 'border-red-500/30 dark:border-red-400/25 bg-red-50 dark:bg-red-500/10',
    icon: 'text-red-600 dark:text-red-400',
    title: 'text-red-900 dark:text-red-100',
    role: 'alert',
    path: 'M12 9v3.75m0 3.75h.008v.008H12v-.008zM21 12a9 9 0 11-18 0 9 9 0 0118 0z',
  },
} as const;

const v = VARIANTS[severity];
const heading = title ?? v.label;
---

<div
  role={v.role}
  aria-label={heading}
  class:list={['flex items-start gap-3 rounded-xl border p-4', v.box]}
  data-dismissible={dismissible ? 'true' : undefined}
>
  <svg aria-hidden="true" class:list={['mt-0.5 h-5 w-5 shrink-0', v.icon]} fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
    <path stroke-linecap="round" stroke-linejoin="round" d={v.path} />
  </svg>
  <div class="min-w-0 flex-1">
    <p class:list={['m-0 text-sm font-semibold', v.title]}>{heading}</p>
    <div class="mt-0.5 text-sm leading-relaxed text-secondary-700 dark:text-secondary-300 [&_p]:m-0 [&_p+p]:mt-1.5">
      <slot />
    </div>
  </div>
  {dismissible && (
    <button
      type="button"
      aria-label="Dismiss"
      class="alert-dismiss shrink-0 inline-flex h-6 w-6 items-center justify-center rounded-md text-secondary-400 hover:bg-black/5 dark:hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-600"
    >
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><path d="M18 6 6 18" /><path d="m6 6 12 12" /></svg>
    </button>
  )}
</div>

{dismissible && (
  <script>
    document.querySelectorAll('.alert-dismiss').forEach((btn) => {
      btn.addEventListener('click', () => {
        const alertEl = btn.closest('[data-dismissible]');
        alertEl?.remove();
      });
    });
  </script>
)}

Theming

Uses the shared primary-* / accent-* scale — see Theming if colours look unstyled after install.