Basic Popconfirm
The simplest use case of Popconfirm.
Code
<%= render Hakumi::Popconfirm::Component.new(
title: "Delete the task",
description: "Are you sure to delete this task?",
ok_text: "Yes",
cancel_text: "No",
id: "popconfirm-basic"
) do %>
<%= render(Hakumi::Button::Component.new(type: :link)) { "Delete" } %>
<% end %>
<script>
(() => {
const el = document.getElementById("popconfirm-basic")
if (!el) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
el.addEventListener("hakumi-popconfirm:confirm", async () => {
const { instance: n } = await window.HakumiComponents.renderComponent("notification")
n.success("Confirmed", { description: "The task has been deleted." })
})
el.addEventListener("hakumi-popconfirm:cancel", () => {
console.log("Cancelled")
})
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
There are 12 placement options available.
Code
<div class="popconfirm-placement-demo">
<%= render Hakumi::Flex::Component.new(vertical: true, align: :center, gap: :middle) do %>
<%# Top Row %>
<%= render Hakumi::Flex::Component.new(gap: :small, justify: :center) do %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "topLeft") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "TL" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "top") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "Top" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "topRight") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "TR" } %>
<% end %>
<% end %>
<%# Middle Container %>
<%= render Hakumi::Flex::Component.new(justify: :center, gap: 280) do %>
<%# Left Column %>
<%= render Hakumi::Flex::Component.new(vertical: true, gap: :small) do %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "leftTop") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "LT" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "left") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "Left" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "leftBottom") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "LB" } %>
<% end %>
<% end %>
<%# Right Column %>
<%= render Hakumi::Flex::Component.new(vertical: true, gap: :small) do %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "rightTop") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "RT" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "right") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "Right" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "rightBottom") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "RB" } %>
<% end %>
<% end %>
<% end %>
<%# Bottom Row %>
<%= render Hakumi::Flex::Component.new(gap: :small, justify: :center) do %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "bottomLeft") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "BL" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "bottom") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "Bottom" } %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(title: "Title", placement: "bottomRight") do %>
<%= render(Hakumi::Button::Component.new(class: "placement-btn")) { "BR" } %>
<% end %>
<% end %>
<% end %>
</div>
<style>
.popconfirm-placement-demo {
padding: 100px 0;
width: 100%;
display: flex;
justify-content: center;
}
.placement-btn {
width: 80px;
justify-content: center;
}
</style>
Customize Icon
You can customize the icon in the popconfirm.
Code
<%= render Hakumi::Popconfirm::Component.new(
title: "Delete the task",
icon: render(Hakumi::Icon::Component.new(name: "question-circle", style: "color: red"))
) do %>
<%= render(Hakumi::Button::Component.new(type: :link)) { "Delete" } %>
<% end %>
Asynchronous Close
Asynchronously close on OK button click.
Code
<%= render Hakumi::Popconfirm::Component.new(
title: "Delete the task",
description: "Are you sure to delete this task?",
ok_text: "Yes",
cancel_text: "No",
id: "popconfirm-async"
) do %>
<%= render(Hakumi::Button::Component.new(type: :primary)) { "Open Popconfirm with async logic" } %>
<% end %>
<script>
(function() {
const el = document.getElementById('popconfirm-async');
el.addEventListener('hakumi-popconfirm:confirm', async (e) => {
const { instance: n } = await window.HakumiComponents.renderComponent('notification');
n.info('Deleting...', { duration: 2 });
// We just provide the promise, the component handles the rest (loading, close, etc)
e.detail.promise = new Promise(resolve => setTimeout(resolve, 2000))
.then(() => {
n.success('Success', { description: 'Task deleted.' });
});
});
})();
</script>
Auto Shift
Automatically adjust placement when overflowing viewport.
Code
<%= render Hakumi::Flex::Component.new(
vertical: true,
align: :center,
justify: :center,
style: "height: 100vh; width: 100vw; position: relative; overflow: hidden;"
) do %>
<%# Top Edge - Forcing collision %>
<div style="position: absolute; top: 0;">
<%= render Hakumi::Popconfirm::Component.new(title: "I flipped to bottom because I'm on top!", placement: "top") do %>
<%= render(Hakumi::Button::Component.new) { "Target: Top" } %>
<% end %>
</div>
<%# Bottom Edge - Forcing collision %>
<div style="position: absolute; bottom: 0;">
<%= render Hakumi::Popconfirm::Component.new(title: "I flipped to top because I'm on bottom!", placement: "bottom") do %>
<%= render(Hakumi::Button::Component.new) { "Target: Bottom" } %>
<% end %>
</div>
<%# Left Edge - Forcing collision %>
<div style="position: absolute; left: 0;">
<%= render Hakumi::Popconfirm::Component.new(title: "I flipped to right!", placement: "left") do %>
<%= render(Hakumi::Button::Component.new) { "Target: Left" } %>
<% end %>
</div>
<%# Right Edge - Forcing collision %>
<div style="position: absolute; right: 0;">
<%= render Hakumi::Popconfirm::Component.new(title: "I flipped to left!", placement: "right") do %>
<%= render(Hakumi::Button::Component.new) { "Target: Right" } %>
<% end %>
</div>
<%# Center Section demonstrating pure 'auto' placement %>
<%= render Hakumi::Flex::Component.new(vertical: true, align: :center, gap: :middle) do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, align: :center, size: :small) do %>
<%= render Hakumi::Typography::Title::Component.new(level: 4, style: "margin-bottom: 0;") do %>
Auto Placement & Collision
<% end %>
<%= render Hakumi::Typography::Text::Component.new(type: :secondary) do %>
The center button uses <code>placement: "auto"</code>
<% end %>
<% end %>
<%= render Hakumi::Popconfirm::Component.new(
title: "I chose the side with most space!",
description: "In this case, probably top or bottom.",
placement: "auto"
) do %>
<%= render(Hakumi::Button::Component.new(type: :primary, size: :large)) { "Auto Placement Button" } %>
<% end %>
<%= render Hakumi::Typography::Text::Component.new(type: :secondary, style: "font-style: italic; margin-top: 20px;") do %>
Click edge buttons to see collisions, or center button for auto-logic.
<% end %>
<% end %>
<% end %>
Popconfirm Ruby Props
| Prop | Type | Default | Description |
|---|---|---|---|
title |
String |
- |
Title of the confirmation box. |
description |
String |
- |
Description of the confirmation box. |
ok_text |
String |
"OK" |
Text of the Confirm button. |
cancel_text |
String |
"Cancel" |
Text of the Cancel button. |
ok_type |
Symbol |
:primary |
Button type of the Confirm button. |
placement |
String |
"top" |
The position of the popconfirm relative to the target. |
trigger |
String |
"click" |
Popconfirm trigger mode (hover, click, focus). |
disabled |
Boolean |
false |
Whether to disable popconfirm. |
show_cancel |
Boolean |
true |
Whether to show cancel button. |
icon |
String |
- |
Customize the icon. |
auto_adjust_overflow |
Boolean |
true |
Whether to automatically adjust placement when overflowing. |
JavaScript API (element.hakumiComponent.api)
| Prop | Type | Default | Description |
|---|---|---|---|
open() |
Function |
- |
Show the popconfirm manually. |
close() |
Function |
- |
Hide the popconfirm manually. |
confirm() |
Function |
- |
Trigger the confirm action. |
cancel() |
Function |
- |
Trigger the cancel action. |