Popconfirm

Component

Interactive examples and API documentation

Basic Popconfirm
The simplest use case of Popconfirm.
Code
<%= render(HakumiComponents::Popconfirm::Component.new(
  ok_text: "Yes",
  cancel_text: "No",
  id: "popconfirm-basic"
)) do |pc| %>
  <% pc.with_title { "Delete the task" } %>
  <% pc.with_description { "Are you sure to delete this task?" } %>
  <%= render(HakumiComponents::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 HakumiComponents::Flex::Component.new(vertical: true, align: :center, gap: :middle) do %>
    
    <%# Top Row %>
    <%= render HakumiComponents::Flex::Component.new(gap: :small, justify: :center) do %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "topLeft")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "TL" } %>
      <% end %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "top")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "Top" } %>
      <% end %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "topRight")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "TR" } %>
      <% end %>
    <% end %>

    <%# Middle Container %>
    <%= render HakumiComponents::Flex::Component.new(justify: :center, gap: 280) do %>
       <%# Left Column %>
       <%= render HakumiComponents::Flex::Component.new(vertical: true, gap: :small) do %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "leftTop")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "LT" } %>
          <% end %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "left")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "Left" } %>
          <% end %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "leftBottom")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "LB" } %>
          <% end %>
       <% end %>

       <%# Right Column %>
       <%= render HakumiComponents::Flex::Component.new(vertical: true, gap: :small) do %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "rightTop")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "RT" } %>
          <% end %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "right")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "Right" } %>
          <% end %>
          <%= render(HakumiComponents::Popconfirm::Component.new(placement: "rightBottom")) do |pc| %>
            <% pc.with_title { "Title" } %>
            <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "RB" } %>
          <% end %>
       <% end %>
    <% end %>

    <%# Bottom Row %>
    <%= render HakumiComponents::Flex::Component.new(gap: :small, justify: :center) do %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "bottomLeft")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "BL" } %>
      <% end %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "bottom")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::Button::Component.new(class: "placement-btn")) { "Bottom" } %>
      <% end %>
      <%= render(HakumiComponents::Popconfirm::Component.new(placement: "bottomRight")) do |pc| %>
        <% pc.with_title { "Title" } %>
        <%= render(HakumiComponents::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(HakumiComponents::Popconfirm::Component.new) do |pc| %>
  <% pc.with_title { "Delete the task" } %>
  <% pc.with_icon do %>
    <%= render(HakumiComponents::Icon::Component.new(name: "question-circle", style: "color: red")) %>
  <% end %>
  <%= render(HakumiComponents::Button::Component.new(type: :link)) { "Delete" } %>
<% end %>
Asynchronous Close
Asynchronously close on OK button click.
Code
<%= render(HakumiComponents::Popconfirm::Component.new(
  ok_text: "Yes",
  cancel_text: "No",
  id: "popconfirm-async"
)) do |pc| %>
  <% pc.with_title { "Delete the task" } %>
  <% pc.with_description { "Are you sure to delete this task?" } %>
  <%= render(HakumiComponents::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 HakumiComponents::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(HakumiComponents::Popconfirm::Component.new(placement: "top")) do |pc| %>
      <% pc.with_title { "I flipped to bottom because I'm on top!" } %>
      <%= render(HakumiComponents::Button::Component.new) { "Target: Top" } %>
    <% end %>
  </div>

  <%# Bottom Edge - Forcing collision %>
  <div style="position: absolute; bottom: 0;">
    <%= render(HakumiComponents::Popconfirm::Component.new(placement: "bottom")) do |pc| %>
      <% pc.with_title { "I flipped to top because I'm on bottom!" } %>
      <%= render(HakumiComponents::Button::Component.new) { "Target: Bottom" } %>
    <% end %>
  </div>

  <%# Left Edge - Forcing collision %>
  <div style="position: absolute; left: 0;">
    <%= render(HakumiComponents::Popconfirm::Component.new(placement: "left")) do |pc| %>
      <% pc.with_title { "I flipped to right!" } %>
      <%= render(HakumiComponents::Button::Component.new) { "Target: Left" } %>
    <% end %>
  </div>

  <%# Right Edge - Forcing collision %>
  <div style="position: absolute; right: 0;">
    <%= render(HakumiComponents::Popconfirm::Component.new(placement: "right")) do |pc| %>
      <% pc.with_title { "I flipped to left!" } %>
      <%= render(HakumiComponents::Button::Component.new) { "Target: Right" } %>
    <% end %>
  </div>

  <%# Center Section demonstrating pure 'auto' placement %>
  <%= render HakumiComponents::Flex::Component.new(vertical: true, align: :center, gap: :middle) do %>
    
    <%= render HakumiComponents::Space::Component.new(direction: :vertical, align: :center, size: :small) do %>
      <%= render HakumiComponents::Typography::Title::Component.new(level: 4, style: "margin-bottom: 0;") do %>
        Auto Placement & Collision
      <% end %>
      <%= render HakumiComponents::Typography::Text::Component.new(type: :secondary) do %>
        The center button uses <code>placement: "auto"</code>
      <% end %>
    <% end %>

    <%= render(HakumiComponents::Popconfirm::Component.new(
      placement: "auto"
    )) do |pc| %>
      <% pc.with_title { "I chose the side with most space!" } %>
      <% pc.with_description { "In this case, probably top or bottom." } %>
      <%= render(HakumiComponents::Button::Component.new(type: :primary, size: :large)) { "Auto Placement Button" } %>
    <% end %>

    <%= render HakumiComponents::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.
setLoading(loading) Function - Set the loading state of the OK button (true/false).