Basic Notifications
Trigger the default notification types with programmatic rendering.
Code
<%= render Hakumi::Space::Component.new(size: :middle, wrap: true) do %>
<%= render(Hakumi::Button::Component.new(id: "notif-open", type: :default)) { "Open" } %>
<%= render(Hakumi::Button::Component.new(id: "notif-success", type: :primary)) { "Success" } %>
<%= render(Hakumi::Button::Component.new(id: "notif-info", type: :default)) { "Info" } %>
<%= render(Hakumi::Button::Component.new(id: "notif-warning", type: :default)) { "Warning" } %>
<%= render(Hakumi::Button::Component.new(id: "notif-error", type: :primary, danger: true)) { "Error" } %>
<% end %>
<script>
(() => {
const buttons = [
{ id: "notif-open", handler: (n) => n.open({ title: "Notification", description: "This is a basic notification rendered via HakumiComponents." }) },
{ id: "notif-success", handler: (n) => n.success("Success", { description: "Everything worked as expected." }) },
{ id: "notif-info", handler: (n) => n.info("Info", { description: "Here is some useful information." }) },
{ id: "notif-warning", handler: (n) => n.warning("Warning", { description: "Be careful with that action." }) },
{ id: "notif-error", handler: (n) => n.error("Error", { description: "Something went wrong." }) }
]
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
const api = async () => {
const res = await window.HakumiComponents.renderComponent("notification")
return res.instance
}
buttons.forEach(({ id, handler }) => {
const el = document.getElementById(id)
if (!el) return
el.addEventListener("click", async () => {
const instance = await api()
handler(instance)
})
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Placement & Duration
Change placement and duration, including persistent notifications (duration: 0).
Code
<%= render Hakumi::Space::Component.new(size: :middle, wrap: true) do %>
<%= render(Hakumi::Button::Component.new(id: "notif-topleft", type: :default)) { "Top Left (5s)" } %>
<%= render(Hakumi::Button::Component.new(id: "notif-persistent", type: :default)) { "Bottom Right (Persistent)" } %>
<% end %>
<script>
(() => {
const topLeft = document.getElementById("notif-topleft")
const persistent = document.getElementById("notif-persistent")
if (!topLeft || !persistent) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
const api = async () => {
const res = await window.HakumiComponents.renderComponent("notification")
return res.instance
}
topLeft.addEventListener("click", async () => {
const n = await api()
n.open({
title: "Top Left",
description: "This notification will disappear in 5 seconds.",
placement: "topLeft",
duration: 5
})
})
persistent.addEventListener("click", async () => {
const n = await api()
n.open({
title: "Persistent",
description: "This notification will not close automatically.",
placement: "bottomRight",
duration: 0
})
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Update by Key
Open a notification with a key and update it later without creating a new one.
Code
<%= render Hakumi::Space::Component.new(size: :middle, wrap: true) do %>
<%= render(Hakumi::Button::Component.new(id: "notif-update", type: :primary)) { "Open & Update" } %>
<% end %>
<script>
(() => {
const button = document.getElementById("notif-update")
if (!button) return
const key = "updatable-notification"
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
const api = async () => {
const res = await window.HakumiComponents.renderComponent("notification")
return res.instance
}
button.addEventListener("click", async () => {
const n = await api()
n.open({
key,
title: "Loading...",
description: "Doing some work...",
duration: 0
})
setTimeout(() => {
n.open({
key,
type: "success",
title: "Updated!",
description: "Work completed successfully.",
duration: 3
})
}, 2000)
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Max Count & Stack
Limit the number of visible notifications and enable stacked behavior after a threshold.
Code
<%= render Hakumi::Space::Component.new(size: :middle, wrap: true) do %>
<%= render(Hakumi::Button::Component.new(id: "notif-stack", type: :default)) { "Max 3 & Stack" } %>
<% end %>
<script>
(() => {
const button = document.getElementById("notif-stack")
if (!button) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
const api = async () => {
const res = await window.HakumiComponents.renderComponent("notification")
return res.instance
}
button.addEventListener("click", async () => {
const n = await api()
n.config({ maxCount: 3, stackThreshold: 2 })
for (let i = 1; i <= 5; i += 1) {
n.open({
title: `Notification ${i}`,
description: `Notice number ${i} in the stack.`,
duration: 10
})
}
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Progress & Pause on Hover
Show a progress bar and pause the auto-close timer while hovering.
Code
<%= render Hakumi::Space::Component.new(size: :middle, wrap: true) do %>
<%= render(Hakumi::Button::Component.new(id: "notif-progress", type: :default)) { "Progress & Pause" } %>
<% end %>
<script>
(() => {
const button = document.getElementById("notif-progress")
if (!button) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
const create = async () => {
const res = await window.HakumiComponents.renderComponent("notification")
return res.instance
}
button.addEventListener("click", async () => {
const n = await create()
n.open({
title: "Progress Bar",
description: "Hover over me to pause the timer and progress bar.",
duration: 10,
showProgress: true,
pauseOnHover: true
})
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Notification API
| Prop | Type | Default | Description |
|---|---|---|---|
title |
String |
- |
Notification title (Hakumi: message). |
description |
String |
- |
Notification body text. |
type |
Symbol |
- |
Type (:success, :info, :warning, :error). |
duration |
Number |
4.5 |
Seconds before auto close. Use 0 to persist. |
key |
String |
- |
Unique key for updating an existing notification. |
placement |
String |
"topRight" |
Placement (topRight, topLeft, bottomRight, bottomLeft, top, bottom). |
icon |
String |
- |
Override the icon (success/info/warning/error) or provide custom markup. |
close_icon |
String|false |
- |
Override the close icon. Use false to hide the close button. |
btn |
String |
- |
Optional action area content (simple text/markup). |
class_name |
String |
- |
Extra CSS class for the notice. |
style |
Object |
- |
Inline style object applied to the notice element. |
max_count |
Number |
- |
Maximum visible notices before removing the oldest. |
top |
Number |
24 |
Top offset in pixels for top placements. |
bottom |
Number |
24 |
Bottom offset in pixels for bottom placements. |
pause_on_hover |
Boolean |
true |
Pause the auto-close timer on hover. |
show_progress |
Boolean |
false |
Show a progress bar for auto-close duration. |
stack_threshold |
Number |
3 |
Enable stacked layout when notices exceed this threshold. |
**html_options |
Keyword args |
- |
Extra HTML attributes for the container. |
JavaScript API
Methods available on the DOM element via <code>element.hakumiComponent.api</code> (or registry instance).
| Prop | Type | Default | Description |
|---|---|---|---|
open(options) |
Function |
- |
Open or update a notification with the provided options. |
success(options) |
Function |
- |
Shortcut for a success notification. |
info(options) |
Function |
- |
Shortcut for an info notification. |
warning(options) |
Function |
- |
Shortcut for a warning notification. |
error(options) |
Function |
- |
Shortcut for an error notification. |
close(key) |
Function |
- |
Close a notification by key. |
destroy(key?) |
Function |
- |
Destroy a single notification by key, or all notifications if no key is provided. |
config(options) |
Function |
- |
Update global configuration (placement, duration, maxCount, offsets, RTL, etc.). |
getState() |
Function |
- |
Return current count and configuration. |