Alert
useAlert(options) creates a .alert with role="alert" for warning/danger and role="status" for info/success. Dismissible alerts get a button with aria-label="Dismiss". alertClass(options) returns the classes for SSR markup.
Variants
import { useAlert } from "@katanakit/ui";
stack.append(
useAlert({ variant: "info", title: "Heads up", message: "Deploy starts in 10 minutes." }),
useAlert({ variant: "success", message: "Backup finished." }),
useAlert({ variant: "warning", message: "Quota at 90%." }),
useAlert({ variant: "danger", title: "Build failed", message: "Check the logs." }),
);Dismissible
useAlert({
variant: "info",
message: "This one can be dismissed.",
dismissible: true,
onDismiss: () => console.log("closed"),
});Contract
Every component in the kit follows one shape. Pure builders return a class string and touch nothing; factories build a DOM element and need a browser.
| Surface | Import | Needs a DOM |
|---|---|---|
| Pure class builder | alertClass | No — safe during SSR |
| Element factory | useAlert | Yes — throws with a pointer to the pure surface |
// Server and templates — pure
<div class={ alertClass({ /* … */ }) }></div>
// Browser — imperative
document.body.append(useAlert({ /* … */ }));Class names are unprefixed. The root class is alert, not kk-alert, and every component rule is wrapped in @layer katana.
That matters because these names collide 1:1 with daisyUI. Unlayered CSS always beats layered CSS regardless of specificity or import order, so loading both is deterministic instead of "whoever came last". See why.
Options
| Option | Type | Default | Notes |
|---|---|---|---|
variant | "info" | "success" | "warning" | "danger" | "info" | Colors and ARIA role. |
title | string | — | Bold title line. |
message | string | — | Body text. |
dismissible | boolean | false | Adds the accessible close button. |
onDismiss | () => void | — | Called after the alert is removed. |
SSR
The factory needs a DOM. On the server use alertClass() and render the markup yourself — the classes are stable strings.