Basic Modal
Basic modal dialog.
Code
<%= render(HakumiComponents::Button::Component.new(type: :primary, data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "basic-modal"
})) { "Open Modal" } %>
<%= render(HakumiComponents::Modal::Component.new(
id: "basic-modal",
open: false
)) do |modal| %>
<% modal.with_header { "Basic Modal" } %>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
<% end %>
Modal with Custom Footer
Modal with custom footer.
Code
<%= render(HakumiComponents::Button::Component.new(type: :primary, data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "custom-footer-modal"
})) { "Open Modal with Custom Footer" } %>
<%= render(HakumiComponents::Modal::Component.new(
id: "custom-footer-modal",
open: false
)) do |modal| %>
<% modal.with_header { "Modal with Custom Footer" } %>
<% modal.with_footer do %>
<%= render(HakumiComponents::Button::Component.new(data: { "hakumi-modal-close": true })) { "Return" } %>
<%= render(HakumiComponents::Button::Component.new(type: :primary, loading: true, data: { "hakumi-modal-ok": true })) { "Submit" } %>
<% end %>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
<% end %>
Loading Status
Modal with loading status.
Code
<%= render(HakumiComponents::Button::Component.new(type: :primary, data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "loading-modal"
})) { "Open Modal with Loading" } %>
<%= render(HakumiComponents::Modal::Component.new(
id: "loading-modal",
open: false,
confirm_loading: true
)) do |modal| %>
<% modal.with_header { "Modal with Loading Status" } %>
<p>When clicking the OK button, it will enter loading state and close after 2 seconds.</p>
<p>Click OK to see the loading effect.</p>
<% modal.with_footer do %>
<%= render(HakumiComponents::Button::Component.new(data: { "hakumi-action": "cancel" })) { "Cancel" } %>
<%= render(HakumiComponents::Button::Component.new(type: :primary, data: { "hakumi-action": "confirm" })) { "OK" } %>
<% end %>
<% end %>
Async Logic
Modal with async logic.
Code
<%= render(HakumiComponents::Button::Component.new(type: :primary, id: "async-modal-btn")) { "Open Modal with Async Logic" } %>
<%= render(HakumiComponents::Modal::Component.new(
id: "async-modal",
open: false,
confirm_loading: false
)) do |modal| %>
<% modal.with_header { "Async Modal" } %>
<p>The modal will be closed after two seconds</p>
<% end %>
<script>
(() => {
const button = document.getElementById("async-modal-btn")
if (!button) return
button.addEventListener("click", () => {
const modal = document.getElementById("async-modal")
if (!modal?.hakumiComponent?.api) return
modal.hakumiComponent.api.open()
// Auto-close after 2 seconds
setTimeout(() => {
modal.hakumiComponent.api.close()
}, 2000)
})
})()
</script>
Modal Cannot be Closed by Backdrop
Modal with mask_closable set to false prevents closing by clicking the backdrop.
Code
<%= render(HakumiComponents::Button::Component.new(type: :primary, data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "mask-closable-modal"
})) { "Open Modal (Cannot close with backdrop)" } %>
<%= render(HakumiComponents::Modal::Component.new(
id: "mask-closable-modal",
open: false,
mask_closable: false
)) do |modal| %>
<% modal.with_header { "Modal with mask_closable: false" } %>
<p>This modal cannot be closed by clicking on the backdrop.</p>
<p>You must use the X button or the Cancel/OK buttons to close it.</p>
<% end %>
Confirmation Modal
Different types of confirmation modals with appropriate icons and styling.
Code
<%= render HakumiComponents::Space::Component.new(size: :small, wrap: true) do %>
<%= render(HakumiComponents::Button::Component.new(data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "confirm-modal"
})) { "Confirm" } %>
<%= render(HakumiComponents::Modal::Confirm::Component.new(
id: "confirm-modal",
title: "Confirm",
open: false
)) { "Do you want to delete these items?" } %>
<%= render(HakumiComponents::Button::Component.new(data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "info-modal"
})) { "Info" } %>
<%= render HakumiComponents::Modal::Info::Component.new(
id: "info-modal",
title: "Info",
message: "This is an informational message.",
open: false
) %>
<%= render(HakumiComponents::Button::Component.new(data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "success-modal"
})) { "Success" } %>
<%= render HakumiComponents::Modal::Success::Component.new(
id: "success-modal",
title: "Success",
message: "The operation completed successfully!",
open: false
) %>
<%= render(HakumiComponents::Button::Component.new(data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "error-modal"
})) { "Error" } %>
<%= render HakumiComponents::Modal::Error::Component.new(
id: "error-modal",
title: "Error",
message: "An error occurred while processing your request.",
open: false
) %>
<%= render(HakumiComponents::Button::Component.new(data: {
controller: "hakumi--modal-trigger",
hakumi__modal_trigger_modal_id_value: "warning-modal"
})) { "Warning" } %>
<%= render HakumiComponents::Modal::Warning::Component.new(
id: "warning-modal",
title: "Warning",
message: "This action cannot be undone.",
open: false
) %>
<% end %>
Programmatic Modal
Render a modal via the component API endpoint and inject it into the page.
Code
<div class="hakumi-space hakumi-space-horizontal" style="gap: 12px;">
<%= render(HakumiComponents::Button::Component.new(type: :primary, id: "programmatic-modal-btn")) { "Render Modal via API" } %>
<div id="programmatic-modal-target"></div>
</div>
<script>
(() => {
const button = document.getElementById("programmatic-modal-btn")
if (!button) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
button.addEventListener("click", async () => {
const result = await window.HakumiComponents.renderComponent("modal", {
target: "#programmatic-modal-target",
mode: "destroy_on_close",
params: {
title: "Programmatic Modal",
message: "This modal was created using HakumiComponents.renderComponent() API",
open: true
}
})
// Modal opens automatically with open: true param
// No need to call result.instance?.open()
})
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>
Modal API
| Prop | Type | Default | Description |
|---|---|---|---|
open |
Boolean |
false |
Controls visibility. |
title |
String or ViewComponent |
- |
Modal header title. |
width |
Integer |
520 |
Modal width in pixels. |
centered |
Boolean |
false |
Vertically center modal. |
footer |
Boolean or ViewComponent |
nil |
Custom footer content; set to false to hide. |
closable |
Boolean |
true |
Show close button. |
mask |
Boolean |
true |
Render backdrop. |
mask_closable |
Boolean |
true |
Allow closing by clicking mask. |
keyboard |
Boolean |
true |
Close on ESC key. |
on_ok |
Proc |
- |
Callback invoked on primary button. |
on_cancel |
Proc |
- |
Callback invoked on cancel button or close action. |
confirm_loading |
Boolean |
false |
Loading state for primary button. |
ok_text |
String |
\"OK\" |
Primary button label. |
cancel_text |
String |
\"Cancel\" |
Cancel button label. |
ok_button_props |
Hash |
{} |
Props for the primary button. Supports Button props like size:, type:, disabled:, icon:, etc. |
cancel_button_props |
Hash |
{} |
Props for the cancel button. Supports Button props like size:, type:, disabled:, icon:, etc. |
content slot |
Slot |
- |
Modal body content. |
**html_attributes |
Keyword args |
- |
Attributes merged into the root `.hakumi-modal-root` (pass as kwargs such as `class:`, `style:`). |
JavaScript API
Access via element.hakumiComponent.api
| Prop | Type | Default | Description |
|---|---|---|---|
open() |
Method |
- |
Open the modal |
close() |
Method |
- |
Close the modal |
toggle() |
Method |
- |
Toggle the modal open or closed |
isOpen() |
Method |
- |
Check if the modal is currently open |
getState() |
Method |
- |
Get current modal state |