AdminKitDocs
Components

Next.js Bootstrap Alerts

A Next.js Bootstrap alert for App Router pages: theme colors, icons and outline styles, and a dismissible variant that a server component can render.

Alerts tell the user what just happened, or what needs their attention, right where it matters on the page. Alert brings Bootstrap's alert to your Next.js pages, in any theme color and with an optional close button. It is in the free and PRO versions of AdminKit for Next.js.

Alert is a client component: its file starts with "use client", so it also runs in the browser. That is how a dismissible alert keeps its own open state and fades out with Bootstrap's transition, without Bootstrap's JavaScript.

Your page does not need to be a client component for that. In the App Router, pages are server components. They can pass plain values to a client component, but not functions. variant and dismissible are a string and a boolean, so your page renders Alert directly, dismissible or not, as the demo's alerts page does. Only onClose is a function, so only an alert with onClose needs a client component of your own.

Example

The alert itself has no padding in AdminKit. Wrap the text in .alert-message:

src/app/(dashboard)/billing/page.tsx
import { Alert } from "@/components/bootstrap/alert";
import { pageMetadata } from "@/lib/site";

export const metadata = pageMetadata("/billing");

export default function BillingPage() {
  return (
    <>
      <h1 className="h3 mb-3">Billing</h1>
      <Alert variant="primary">
        <div className="alert-message">Your trial ends in 7 days.</div>
      </Alert>
      <Alert variant="success">
        <div className="alert-message">Your changes have been saved.</div>
      </Alert>
      <Alert variant="danger">
        <div className="alert-message">The payment failed. Check your card details.</div>
      </Alert>
      <Alert variant="warning">
        <div className="alert-message">Your storage is almost full.</div>
      </Alert>
    </>
  );
}

pageMetadata() reads the page's title and description from src/data/pages.json, so a new page needs an entry there (see Add a page).

Props

PropTypeDefaultDescription
variantstring"primary"The color: adds .alert-<variant>, such as success or danger
dismissiblebooleanAdds a close button; the alert fades out when it is clicked
onClose() => voidCalled once a dismissed alert has faded out; needs a client component

Other props, such as className and id, go to the .alert element, which has role="alert". The component is in src/components/bootstrap/alert.tsx.

Dismissing

Let the user close an alert they have read with dismissible. It adds a close button before the children, with .alert-dismissible and .fade. After a click, the alert fades out and renders nothing.

<Alert variant="warning" dismissible>
  <div className="alert-message">
    <strong>Heads up!</strong> Two invoices are past their due date.
  </div>
</Alert>

Closing an alert only lasts until the next page load, when the alert is back. To keep it closed, store that yourself from onClose, for example in localStorage. That takes a client component:

src/components/storage-notice.tsx
"use client";

import { Alert } from "@/components/bootstrap/alert";

export function StorageNotice() {
  return (
    <Alert
      variant="warning"
      dismissible
      onClose={() => localStorage.setItem("storage-notice", "closed")}
    >
      <div className="alert-message">Your storage is almost full.</div>
    </Alert>
  );
}

Read the stored value in an effect, which runs after hydration: the moment the browser takes over the HTML that Next.js built. Only then decide whether to render the alert. This keeps the server HTML and the first browser render the same.

Icons and outline styles

For an icon column, put an .alert-icon element before the message. alert-outline gives the alert a neutral background and a gray border, and keeps the icon column in the theme color. alert-outline-coloured colors the border too.

import { Bell } from "lucide-react";
import { Alert } from "@/components/bootstrap/alert";

export function NotificationAlerts() {
  return (
    <>
      <Alert variant="primary" dismissible>
        <div className="alert-icon">
          <Bell className="align-middle" />
        </div>
        <div className="alert-message">You have 3 new notifications.</div>
      </Alert>
      <Alert variant="primary" className="alert-outline-coloured" dismissible>
        <div className="alert-icon">
          <Bell className="align-middle" />
        </div>
        <div className="alert-message">You have 3 new notifications.</div>
      </Alert>
    </>
  );
}

Additional content

An alert can hold a whole message: a heading with .alert-heading, paragraphs, a divider and links. .alert-link gives a link the alert's color. For links to other pages of the app, use Link from next/link:

<Alert variant="success">
  <div className="alert-message">
    <h2 className="h4 alert-heading">Import finished</h2>
    <p>1,240 customers were imported. 3 rows were skipped because the email address was missing.</p>
    <hr />
    <p className="mb-0">
      <Link href="/customers" className="alert-link">Review the customers</Link>
    </p>
  </div>
</Alert>

Accessibility

  • Alert sets role="alert": screen readers announce it when it appears. Pass role="status" for a message that can wait. Your props override the default.
  • The close button has aria-label="Close".
  • After a close, the focused button is gone. In a task flow, move the focus to the next relevant element from onClose.
  • Say in the text what kind of message it is. The color alone does not tell everyone.

Last updated on

On this page