For the Rails version of the dialog kit, the clickable element being used to open the dialog must be given a open-dialog data attribute with a value that is the same as the id being given to the dialog itself. See code example below to see this in action.
Additionally, both the cancel button and the confirm button have optional id props which can be used to pass in a custom id to allow developers to target that button with custom javascript if needed (confirm_button_id and cancel_button_id).
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-1"} }) %> <%= pb_rails("dialog", props: { id:"dialog-1", size: "sm", title: "Header Title is the Title Prop", text: "Hello Body Text, Nice to meet ya.", cancel_button: "Cancel Button", confirm_button: "Okay", confirm_button_id: "confirm-button-1" }) %>
The dialog kit also supports customizing your dialog with a compound component structure.
This allows for greater flexibility and more complex dialogs.
For the Rails version, when using the kit as a compound component it is necessary to pass the same value as the id for the dialog, the dialog header and the dialog footer in order for the opening and closing of the dialog to function as expected.
If you are using the datepicker within the Rails dialog, do not use the static_position prop on the datepicker.
<% options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Pakistan", value: "pakistan", id: "pk" } ] %> <%= pb_rails("button", props: { text: "Open Complex Dialog", data:{"open-dialog": "dialog-complex"} }) %> <%= pb_rails("dialog", props: { id:"dialog-complex", size: "lg", full_height: true }) do %> <%= pb_form_with(scope: :example, method: :get, url: "", options: { remote: true }) do |form| %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-complex" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <%= pb_rails("dropdown", props: {options: options, autocomplete: true}) %> <%= pb_rails("typeahead", props: { id: "typeahead-default", placeholder: "Select one...", options: options, name: :foo, margin_top: "sm", is_multi: false }) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-complex"}) %> <% end %> <% end %>
<%= pb_rails("button", props: { text: "Small Dialog", data:{"open-dialog": "dialog-sm"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Medium Dialog", data:{"open-dialog": "dialog-md"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Large Dialog", data:{"open-dialog": "dialog-lg"}, margin_right: "md" }) %> <%= pb_rails("dialog", props: { id:"dialog-sm", size: "sm", title: "Header on small dialog", text: "Body on small dialog", cancel_button: "Cancel", confirm_button: "Okay", }) %> <%= pb_rails("dialog", props: { id:"dialog-md", size: "md", title: "Title on medium dialog", text: "Body on medium dialog", cancel_button: "Cancel", confirm_button: "Okay", }) %> <%= pb_rails("dialog", props: { id:"dialog-lg", size: "lg", title: "Header on large dialog", text: "Body on large dialog", cancel_button: "Cancel", confirm_button: "Okay" }) %>
The dialog will create a scroll container automatically when the text exceeds the height of the page. No prop or configuration is needed.
When such a scroll container is created, the dialog header will remain fixed at top of dialog and not scroll with the body content.
If the dialog is a fullHeight variant, the header and footer will both be sticky and not scroll with the body content.
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-scroll"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Open Full Height Dialog", data: {"open-dialog": "dialog-scroll-full-height"}, margin_right: "md" }) %> <%= pb_rails("dialog", props: { id:"dialog-scroll", size: "md", title: "Header Title is the Title Prop", text: "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", cancel_button: "Cancel", confirm_button: "Confirm", confirm_button_id: "confirm-button-1" }) %> <%= pb_rails("dialog", props: { full_height: true, id:"dialog-scroll-full-height", size: "sm", title: "Header Title is the Title Prop", text: "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident.", cancel_button: "Cancel", confirm_button: "Confirm", confirm_button_id: "confirm-button-1" }) %>
When shouldCloseOnOverlayClick is explicitly set to false, click events on the overlay will not close the modal.
By default, shouldCloseOnOverlayClick is set to true.
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-overlay-click"} }) %> <%= pb_rails("dialog", props: { id:"dialog-overlay-click", size: "sm", title: "Neat Header", text: "Click on the overlay all day. I will stay open.", cancel_button: "Cancel", confirm_button: "Okay", confirm_button_id: "confirm-button-1", should_close_on_overlay_click: false, }) %>
The Dialog kit also offers customizable Status Alert options as seen here.
For the rails version of the kit, when using custom confirm and cancel buttons as shown in these examples, the 'cancel' button must be given a close-dialog data attribute with a value that is the same as the id given to the dialog itself.
<%= pb_rails("flex", props:{ gap: "xs", wrap:true}) do %> <%= pb_rails("button", props: { text: "Default Status", data: {"open-dialog": "dialog-status-default"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Caution Status", data: {"open-dialog": "dialog-status-caution"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Delete Status", data: {"open-dialog": "dialog-status-delete"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Information Status", data: {"open-dialog": "dialog-status-info"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Error Status", data: {"open-dialog": "dialog-status-error"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Success Status", data: {"open-dialog": "dialog-status-success"}, margin_right: "md" }) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-default", status: "default", size: "status_size", title: "Are you sure?", text: "Text explaining why there is an alert", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Action" }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", data: {"close-dialog": "dialog-status-default" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-info", status: "info", size: "status_size", title: "Information", text: "Text explaining why there is an alert", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Ok, Thanks!", full_width: true, data: {"close-dialog": "dialog-status-info" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-caution", status: "caution", size: "status_size", title: "Are you Sure?", text: "This is the action you will be taking", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Action" }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", data: {"close-dialog": "dialog-status-caution" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-delete", status: "delete", size: "status_size", title: "Delete", text: "You are about to delete ...", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Delete", variant: "danger" }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", data: {"close-dialog": "dialog-status-delete" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-error", status: "error", size: "status_size", title: "Error Message", text: "Text explaining the error", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Oh no!", full_width: true, data: {"close-dialog": "dialog-status-error" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-status-success", status: "success", size: "status_size", title: "Success!", text: "Text explaining what is successful", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { spacing:"between", padding_x:"md", padding_bottom:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Great!", full_width: true, data: {"close-dialog": "dialog-status-success" } }) %> <% end %> <% end %> <% end %>
These examples highlight how the buttons within the Dialog can be stacked when using the Status Alert variant. It also has a link style for the buttons for the mobile views.
<%= pb_rails("button", props: { text: "Default Status", data: {"open-dialog": "dialog-stacked-default"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Caution Status", data: {"open-dialog": "dialog-stacked-caution"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Delete Status", data: {"open-dialog": "dialog-stacked-delete"}, margin_right: "md" }) %> <%= pb_rails("dialog", props: { id:"dialog-stacked-default", status: "default", size: "sm", title: "Are you sure?", text: "Text explaining why there is an alert", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { orientation: "column", padding_x:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Action", full_width: true }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", full_width: true, margin_top: "sm", data: {"close-dialog": "dialog-stacked-default" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-stacked-caution", status: "caution", size: "sm", title: "Are you sure?", text: "This is the action you will be taking", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { orientation: "column", padding_x:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Action", full_width: true }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", full_width: true, margin_top: "sm", data: {"close-dialog": "dialog-stacked-caution" } }) %> <% end %> <% end %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-stacked-delete", status: "delete", size: "sm", title: "Delete", text: "You are about to delete ...", }) do %> <%= pb_rails("dialog/dialog_footer") do %> <%= pb_rails("flex", props: { orientation: "column", padding_x:"md", padding: "sm" }) do %> <%= pb_rails("button", props: { text: "Yes, Action", variant: "danger", full_width: true }) %> <%= pb_rails("button", props: { text: "No, Cancel", variant: "secondary", full_width: true, margin_top: "sm", data: {"close-dialog": "dialog-stacked-delete" } }) %> <% end %> <% end %> <% end %>
To render a full height Dialog, use the fullHeight (react) or full_height (rails) prop. A full height Dialog can be size small, medium, or large. By default it will be center aligned.
<%= pb_rails("button", props: { text: "Small Dialog", data:{"open-dialog": "dialog-fullheight-sm"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Medium Dialog", data:{"open-dialog": "dialog-fullheight-md"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Large Dialog", data:{"open-dialog": "dialog-fullheight-lg"}, margin_right: "md" }) %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-sm", size: "sm", full_height: true, }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-sm" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-7"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-sm"}) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-md", size: "md", full_height: true, }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-md" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-8"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-md"}) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-lg", size: "lg", full_height: true, }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-lg" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-9"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-lg"}) %> <% end %>
The full height dialog is centered by default, but the placement can be changed via the placement prop with one of the following values: left, center, right.
The large variant however will always be centered, even if the placement prop is used.
All dialogs with the fullHeight prop will be displayed full-width on mobile screens.
<%= pb_rails("button", props: { text: "Left Dialog", data:{"open-dialog": "dialog-fullheight-left"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Center Dialog", data:{"open-dialog": "dialog-fullheight-center"}, margin_right: "md" }) %> <%= pb_rails("button", props: { text: "Right Dialog", data:{"open-dialog": "dialog-fullheight-right"}, margin_right: "md" }) %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-left", size: "md", full_height: true, placement: "left", }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-left" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-2"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-left"}) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-center", size: "md", full_height: true, placement: "center", }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-center" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-3"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-center"}) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-fullheight-right", size: "md", full_height: true, placement: "right", }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-fullheight-right" } ) do %> <%= pb_rails("body", props: { text: "What do you need us to take care of?" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %> <%= pb_rails("textarea", props: {id: "default-4"}) %> <%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %> <%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Back", confirm_button: "Send my Issue", confirm_button_id:"confirm-complex", id: "dialog-fullheight-right"}) %> <% end %>
Pressing the "Okay" button will trigger a loading state where the button content is replaced by a spinner icon and both buttons are disabled.
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-loading"} }) %> <%= pb_rails("dialog", props: { id:"dialog-loading", size: "sm", title: "Loading Example", text: "Make a loading request?", cancel_button: "Cancel Button", cancel_button_id: "cancel-button-loading", confirm_button: "Okay", confirm_button_id: "confirm-button-loading", loading: true, }) %> <script> const loadingButton = document.querySelector('[data-disable-with="Loading"]'); if (loadingButton) { loadingButton.addEventListener("click", function() { const okayLoadingButton = document.querySelector('[data-disable-with="Loading"]'); const cancelButton = document.querySelector('[data-disable-cancel-with="Loading"]'); let currentClass = okayLoadingButton.className; let cancelClass = cancelButton ? cancelButton.className : ""; okayLoadingButton.disabled = true; okayLoadingButton.classList.add("pb_button_loading"); okayLoadingButton.classList.remove("pb_button_enabled"); okayLoadingButton.classList.add("pb_button_disabled"); if (cancelButton) { cancelButton.disabled = true; cancelButton.classList.remove("pb_button_enabled"); cancelButton.classList.add("pb_button_disabled"); } setTimeout(function() { okayLoadingButton.disabled = false; okayLoadingButton.classList.remove("pb_button_loading"); okayLoadingButton.classList.remove("pb_button_disabled"); okayLoadingButton.classList.add("pb_button_enabled"); if (cancelButton) { cancelButton.disabled = false; cancelButton.classList.remove("pb_button_disabled"); cancelButton.classList.add("pb_button_enabled"); } }, 5000); }); } </script>
The custom_event_type prop allows you to specify custom events that will trigger the dialog's initialization or control its behavior. This is especially useful when working with Turbo Frame updates where standard DOM events might not suffice.
The examples demonstrate two use cases:
1) Opening a dialog via custom event dispatch: The first example shows how to configure a dialog to listen for a specific custom event (dialogOpen). When this event is dispatched, the dialog will automatically open, making it easy to trigger the dialog from JavaScript or after Turbo Frame operations.
2) Controlling dialog button actions with custom events: The second example demonstrates how to set up a dialog that can have its confirm button triggered through external events (turboResponse). This pattern is useful when you need to programmatically confirm a dialog after some background operation completes.
3) Multiple custom events: The third example combines the first two to show how custom_event_type prop can support multiple event types separated by a comma.
For Turbo integration, you can use standard Turbo events like turbo:frame-load or turbo:submit-end as your custom_event_type to ensure the dialog responds properly after Turbo navigation or form submissions. The dialog component will listen for these events automatically.
The implementation handles various actions including 'open', 'close', 'clickConfirm', and 'clickCancel', making it flexible for different interaction patterns in your Turbo-enhanced application.
<%= pb_rails("flex", props:{ gap: "xs", wrap:true}) do %> <%= pb_rails("button", props: { id: "button-open-example-turbo-frames", margin_right: "md", text: "Open Dialog via Custom Event" }) %> <%= pb_rails("button", props: { id: "open-dialog-button", data: { open_dialog: "dialog-confirm-turbo-frames" }, margin_right: "md", text: "Custom Event Linked to Confirm Button" }) %> <%= pb_rails("button", props: { id: "button-open-multi-dialog", text: "Mutliple Events Example" }) %> <% end %> <!-- Example 1: Basic dialog with custom event opening --> <%= pb_rails("dialog", props: { id: "dialog-open-turbo-frames", title: "Click Event Simulation", text: "Demonstrating Opening the Dialog with a Custom Event.", custom_event_type: "dialogOpen", cancel_button: "Cancel Button", confirm_button: "Okay", confirm_button_id: "confirm-button-turbo-frames" }) %> <script> document.getElementById("button-open-example-turbo-frames").addEventListener("click", () => { console.log("📣 Dispatching 'dialogOpen' custom event") window.dispatchEvent(new CustomEvent("dialogOpen", { bubbles: true, detail: { dialogId: "dialog-open-turbo-frames", action: "open" } })) console.log("✅ Custom event dispatched - dialog should open") }) </script> <!-- Example 2: Dialog with custom event linking confirm button to closing the dialog--> <%= pb_rails("dialog", props: { id: "dialog-confirm-turbo-frames", title: "Custom Event Button Action", text: "Clicking this dialog's confirm button triggers closing the dialog as well.", custom_event_type: "turboResponse", cancel_button: "Cancel", cancel_button_id: "cancel-button-id-turbo-frames", confirm_button: "Confirm Button", confirm_button_id: "confirm-button-id-turbo-frames" }) %> <script> window.addEventListener("turboResponse", (event) => { const { dialogId, action, cancelButtonId } = event.detail || {} console.log("📦 turboResponse event triggered:", { dialogId, action, cancelButtonId }) if (action === "close" && cancelButtonId) { const dialog = document.getElementById(dialogId) if (dialog?.close) { console.log("🚪 Closing dialog programmatically") dialog.close() } } }) document.getElementById("confirm-button-id-turbo-frames").addEventListener("click", function () { console.log("✅ Confirm button clicked! Triggering cancel via turboResponse") window.dispatchEvent(new CustomEvent("turboResponse", { detail: { dialogId: "dialog-confirm-turbo-frames", action: "close", cancelButtonId: "cancel-button-id-turbo-frames" } })) }) </script> <!-- Example 3: Dialog with multiple custom event types --> <%= pb_rails("dialog", props: { id: "multi-event-dialog", title: "Multiple Event Types", text: "This dialog responds to multiple custom event types - see console logs.", custom_event_type: "dialogOpenMutli,turboResponseMulti", cancel_button: "Cancel", cancel_button_id: "multi-event-cancel", confirm_button: "Confirm", confirm_button_id: "multi-event-confirm" }) %> <script> document.getElementById("button-open-multi-dialog").addEventListener("click", () => { console.log("📣 Dispatching 'dialogOpenMutli' custom event") window.dispatchEvent(new CustomEvent("dialogOpenMutli", { detail: { dialogId: "multi-event-dialog", action: "open" } })) }) document.getElementById("multi-event-confirm")?.addEventListener("click", function() { console.log("✅ Confirm clicked — dispatching 'turboResponseMulti' to simulate dialog close") window.dispatchEvent(new CustomEvent("turboResponseMulti", { detail: { dialogId: "multi-event-dialog", action: "close", cancelButtonId: "multi-event-cancel" } })) }) window.addEventListener("turboResponseMulti", (event) => { const { dialogId, action, cancelButtonId } = event.detail || {} if (action === "close" && dialogId) { const dialog = document.getElementById(dialogId) dialog.close?.() console.log("🚪 Closing dialog programmatically") } }) </script>
Use the overflow: "visible" global prop to allow Typeahead dropdown menus to appear outside the dialog boundaries. By default, dialogs clip content that extends beyond their edges, but this prop enables pop-up elements to render above the dialog overlay.
<% typeahead_options = [ { label: "United States", value: "unitedStates", id: "us" }, { label: "United Kingdom", value: "unitedKingdom", id: "gb" }, { label: "Canada", value: "canada", id: "ca" }, { label: "Australia", value: "australia", id: "au" }, { label: "Germany", value: "germany", id: "de" }, { label: "France", value: "france", id: "fr" }, { label: "Japan", value: "japan", id: "jp" }, { label: "Brazil", value: "brazil", id: "br" } ] %> <%= pb_rails("button", props: { text: "Open Dialog with Overflow Visible", data: {"open-dialog": "dialog-overflow-visible"} }) %> <%= pb_rails("dialog", props: { id: "dialog-overflow-visible", size: "md", overflow: "visible" }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-overflow-visible" } ) do %> <%= pb_rails("body", props: { text: "Select Location" }) %> <% end %> <%= pb_rails("dialog/dialog_body") do %> <%= pb_rails("typeahead", props: { options: typeahead_options, placeholder: "Select a location...", id: "location-typeahead", is_multi: false, }) %> <% end %> <%= pb_rails("dialog/dialog_footer", props: { cancel_button: "Cancel", confirm_button: "Save", confirm_button_id: "confirm-overflow-visible", id: "dialog-overflow-visible" }) %> <% end %>
The closeable prop can be set to false to optionally render the Dialog header without the close “X” button. closeable is set to true by default.
This prop can be used with the simple as well as the complex version of the Dialog as can be seen here.
<%= pb_rails("flex", props:{wrap:true}) do %> <%= pb_rails("button", props: { text: "Open Simple Dialog", data: {"open-dialog": "dialog-simple"}, margin_right:"md" }) %> <%= pb_rails("button", props: { text: "Open Complex Dialog", data: {"open-dialog": "dialog-complex2"} }) %> <% end %> <%= pb_rails("dialog", props: { id:"dialog-simple", size: "sm", title: "Header Title is the Title Prop", text: "Hello Body Text, Nice to meet ya.", cancel_button: "Cancel Button", closeable: false, confirm_button: "Okay", confirm_button_id: "confirm-button-simple" }) %> <%= pb_rails("dialog", props: { id:"dialog-complex2", size: "sm" }) do %> <%= pb_rails("dialog/dialog_header", props: { id: "dialog-complex2", title:"Header Title inside Dialog Header", closeable: false } ) %> <%= pb_rails("dialog/dialog_body", props:{text: "Hello Body Text, Nice to meet ya."}) %> <%= pb_rails("dialog/dialog_footer", props: {cancel_button: "Cancel Button", confirm_button: "Okay", confirm_button_id:"confirm-complex2", id: "dialog-complex2"}) %> <% end %>
<%= pb_rails("fixed_confirmation_toast", props: { text: "Error Message", status: "error", closeable: true })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Items Successfully Moved", status: "success" })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Scan to Assign Selected Items", status: "neutral" })%>
Use the nav_margin_top prop to position the toast lower on the page. This is useful for cases where we want to position the toast below a header or nav.
<%= pb_rails("button", props: { text: "Top Nav Toast", variant: "secondary", data: { toast: "#top-nav" } }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "top-nav-margin", closeable: true, id: "top-nav", multi_line: true, text: "Top nav Margin.", status: "tip", vertical: "top", horizontal: "center", nav_margin_top: true }) %> <script type="text/javascript"> const navtoast = document.querySelectorAll(".top-nav-margin") const navbutton = document.querySelectorAll("button[data-toast]") const hideNavToast = () => { navtoast.forEach((toast) => { toast.style.display = "none" }) } // Hide toasts immediately hideNavToast() // Handle various page load/restore events window.addEventListener('pageshow', hideNavToast) document.addEventListener('DOMContentLoaded', hideNavToast) document.addEventListener('turbolinks:load', hideNavToast) document.addEventListener('turbo:load', hideNavToast) navbutton.forEach((button) => { button.onclick = () => { hideNavToast() let toast = document.querySelector(button.getAttribute("data-toast")) if (toast) { toast.style.display = "flex" } } }) </script>
Multi-line is used when the given text will not fit on one line. Using Multi Line allows the height of the confirmation toast to grow. Simply resize the screen to see the fixed confirmation toast wrap the text.
<%= pb_rails("button", props: { text: "Short Multiline", variant: "secondary", data: { multitoast: "#toast-short" } }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "multitoast-to-hide", closeable: true, id: "toast-short", multi_line: true, text: "Multi-line is used when the given text will not fit on one line.", status: "tip", vertical: "top", horizontal: "center" }) %> <%= pb_rails("button", props: { text: "Long Multiline", variant: "secondary", data: { multitoast: "#toast-long" } }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "multitoast-to-hide", closeable: true, id: "toast-long", multi_line: true, text: "Multi-line is used when the given text will not fit on one line. Using Multi Line allows the height of the confirmation toast to grow. Simply resize the screen to see the fixed confirmation toast wrap the text.", status: "tip", vertical: "top", horizontal: "center" }) %> <script type="text/javascript"> const multitoasts = document.querySelectorAll(".multitoast-to-hide") const multibuttons = document.querySelectorAll("button[data-multitoast]") const hideMultiToasts = () => { multitoasts.forEach((toast) => { toast.style.display = "none" }) } // Hide toasts immediately hideMultiToasts() // Handle various page load/restore events window.addEventListener('pageshow', hideMultiToasts) document.addEventListener('DOMContentLoaded', hideMultiToasts) document.addEventListener('turbolinks:load', hideMultiToasts) document.addEventListener('turbo:load', hideMultiToasts) multibuttons.forEach((button) => { button.onclick = () => { hideMultiToasts() let toast = document.querySelector(button.getAttribute("data-multitoast")) if (toast) { toast.style.display = "flex" } } }) </script>
<%= pb_rails("fixed_confirmation_toast", props: { text: "Error Message", status: "error", closeable: true })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Items Successfully Moved", status: "success", closeable: true })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Scan to Assign Selected Items", status: "neutral", closeable: true })%>
<%= pb_rails("button", props: { text: "Top Center", variant: "secondary", data: { toast: "#toast-top-center" } }) %> <%= pb_rails("button", props: { text: "Top Left", variant: "secondary", data: { toast: "#toast-top-left" } }) %> <%= pb_rails("button", props: { text: "Top Right", variant: "secondary", data: { toast: "#toast-top-right" } }) %> <%= pb_rails("button", props: { text: "Bottom Center", variant: "secondary", data: { toast: "#toast-bottom-center" } }) %> <%= pb_rails("button", props: { text: "Bottom Left", variant: "secondary", data: { toast: "#toast-bottom-left" } }) %> <%= pb_rails("button", props: { text: "Bottom Right", variant: "secondary", data: { toast: "#toast-bottom-right" } }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-top-center", text: "Top Center", status: "neutral", vertical: "top", horizontal: "center" }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-top-left", text: "Top Left", status: "neutral", vertical: "top", horizontal: "left" }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-top-right", text: "Top Right", status: "neutral", vertical: "top", horizontal: "right" }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-bottom-center", text: "Bottom Center", status: "neutral", vertical: "bottom", horizontal: "center" }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-bottom-left", text: "Bottom Left", status: "neutral", vertical: "bottom", horizontal: "left" }) %> <%= pb_rails("fixed_confirmation_toast", props: { classname: "toast-to-hide", closeable: true, id: "toast-bottom-right", text: "Bottom Right", status: "neutral", vertical: "bottom", horizontal: "right" }) %> <script type="text/javascript"> const toasts = document.querySelectorAll(".toast-to-hide") const buttons = document.querySelectorAll("button[data-toast]") const hidePositionToasts = () => { toasts.forEach((toast) => { toast.style.display = "none" }) } // Hide toasts immediately hidePositionToasts() // Handle various page load/restore events window.addEventListener('pageshow', hidePositionToasts) document.addEventListener('DOMContentLoaded', hidePositionToasts) document.addEventListener('turbolinks:load', hidePositionToasts) document.addEventListener('turbo:load', hidePositionToasts) buttons.forEach((button) => { button.onclick = () => { hidePositionToasts() let toast = document.querySelector(button.getAttribute("data-toast")) if (toast) { toast.style.display = "flex" } } }) </script>
Auto close is used when you want the confirmation toast to close automatically after a certain time. auto_close property will be a delay number in ms.
The script tag in this code snippet is for demonstration purposes only. It clones the toasts in order to have it appear with a button click prompt and not upon initial page load. In a typical production environment the event triggering a fixed confirmation toast to appear would be handled by a controller or a separate javascript file.
<%= pb_rails("button", props: { text: "Show Auto Close Toast", variant: "secondary", data: { toast: "#toast-auto-close" } }) %> <%= pb_rails("button", props: { text: "Show Closeable Auto Close Toast", variant: "secondary", data: { toast: "#toast-auto-close-closeable" } }) %> <%= pb_rails("fixed_confirmation_toast", props: { auto_close: 3000, classname: "toast-to-hide", id: "toast-auto-close", text: "I will disappear in 3 seconds.", status: "tip", vertical: "top", horizontal: "center" }) %> <%= pb_rails("fixed_confirmation_toast", props: { auto_close: 10000, closeable: true, id: "toast-auto-close-closeable", text: "I will disappear in 10 seconds.", status: "tip", vertical: "top", horizontal: "center" }) %> <script> // Hide toasts immediately const hideAutoToasts = () => { const toastAuto = document.getElementById('toast-auto-close'); const toastAutoCloseable = document.getElementById('toast-auto-close-closeable'); if (toastAuto) toastAuto.style.display = 'none'; if (toastAutoCloseable) toastAutoCloseable.style.display = 'none'; } hideAutoToasts(); // Handle various page load/restore events window.addEventListener('pageshow', hideAutoToasts) document.addEventListener('turbolinks:load', hideAutoToasts) document.addEventListener('turbo:load', hideAutoToasts) document.addEventListener('DOMContentLoaded', () => { // Initialize toast elements and buttons const toasts = { '#toast-auto-close': document.querySelector("#toast-auto-close"), '#toast-auto-close-closeable': document.querySelector("#toast-auto-close-closeable") } const buttons = { '#toast-auto-close': document.querySelector("button[data-toast='#toast-auto-close']"), '#toast-auto-close-closeable': document.querySelector("button[data-toast='#toast-auto-close-closeable']") } // Store original toasts and remove them from DOM const originalToasts = {} Object.entries(toasts).forEach(([id, toast]) => { if (toast) { originalToasts[id] = toast.cloneNode(true) toast.remove() } }) // Set up button click handlers Object.keys(buttons).forEach((toastId) => { const button = buttons[toastId] if (button) { button.onclick = () => { const newToast = originalToasts[toastId].cloneNode(true) newToast.style.display = "flex" document.body.appendChild(newToast) } } }) }) </script>
Pass anything (including any of our kits) to the children prop to customize the content of the fixed confirmation toast.
NOTE: passing children overrides any content passed to text
<%= pb_rails("fixed_confirmation_toast", props: { padding_y: "none", status: "success" }) do %> <%= pb_rails("title", props: { dark: true, margin_left: "md", text: "Design & Handoff Process was moved to UX Designer Learning Track.", size: 4 }) %> <%= pb_rails("button", props: { dark: true, padding_right: "none", text: "Undo", variant: "link" }) %> <% end %>
<div> <%= pb_rails("fixed_confirmation_toast", props: { icon: "wrench", text: "Fix before proceeding", status: "error", closeable: true, margin_bottom: "md" })%> </div> <div> <%= pb_rails("fixed_confirmation_toast", props: { icon: "star", text: "Thank you for completing the form!", status: "success", margin_bottom: "md" })%> </div> <div> <%= pb_rails("fixed_confirmation_toast", props: { icon: "file-pdf", text: "Saved as PDF", status: "neutral", margin_bottom: "md" })%> </div> <div> <%= pb_rails("fixed_confirmation_toast", props: { icon: "arrow-down", text: "New Messages", status: "tip" })%> </div>
Setting icon prop to "none" will render the fixed confirmation toast without the left side icon.
<%= pb_rails("fixed_confirmation_toast", props: { text: "Error Message", status: "error", icon: "none", closeable: true })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Items Successfully Moved", status: "success", icon: "none" })%> <br><br> <%= pb_rails("fixed_confirmation_toast", props: { text: "Scan to Assign Selected Items", status: "neutral", icon: "none" })%>
<%= pb_rails("flex", props: { dark: true, orientation: "row", vertical: "center" }) do %> <%= pb_rails("body", props: { text: "Click info for more details" }) %> <%= pb_rails("circle_icon_button", props: { variant: "secondary", icon: "info", id: "regular-popover-1" }) %> <%= pb_rails("popover", props: { trigger_element_id: "regular-popover-1", tooltip_id: "tooltip-1", offset: true, position: "top", }) do %> I'm a popover. I can show content of any size. <% end %> <% end %>
Notice offset is not set so the popover is flush with the content.
<%= pb_rails("button", props: { variant: "secondary", id: 'list' }) do %> <%= pb_rails("flex", props: {align: "center"}) do %> Filter By <%= pb_rails("flex/flex_item", props: {margin_left: "xxs"}) do %> <div id="arrow-icon" style="display: flex"> <%= pb_rails("icon", props: { icon: "chevron-down", fixed_width: true }) %> </div> <% end %> <% end %> <% end %> <%= pb_rails("popover", props: {trigger_element_id: "list", tooltip_id: "list-tooltip", position: 'bottom', padding: "none"}) do %> <%= pb_rails("list", props: {ordered: false, dark: false, borderless: false, xpadding: true}) do %> <%= pb_rails("list/item") do %><a>Popularity</a><% end %> <%= pb_rails("list/item") do %><a>Title</a><% end %> <%= pb_rails("list/item") do %><a>Duration</a><% end %> <%= pb_rails("list/item") do %><a>Date Started</a><% end %> <%= pb_rails("list/item") do %><a>Date Ended </a><% end %> <% end %> <% end %> <script type="text/javascript"> const popoverButton = document.querySelector("#list") let buttonClicked = false const arrowDiv = document.querySelector("#arrow-icon") popoverButton.onclick = () => { buttonClicked = !buttonClicked if (buttonClicked) { arrowDiv.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="auto" height="auto" viewBox="0 0 31 25" fill="none" class="pb_custom_icon svg-inline--fa pb_icon_kit svg_fw" id="" data="{}" aria="{}" tabindex=""><path d="M14.2031 5.70312C14.625 5.28125 15.3281 5.28125 15.75 5.70312L24.7969 14.7031C25.2188 15.1719 25.2188 15.875 24.7969 16.2969C24.3281 16.7656 23.625 16.7656 23.2031 16.2969L15 8.09375L6.79688 16.2969C6.32812 16.7656 5.625 16.7656 5.20312 16.2969C4.73438 15.875 4.73438 15.1719 5.20312 14.75L14.2031 5.70312Z" fill="currentColor"/></svg>' } else { arrowDiv.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="auto" height="auto" viewBox="0 0 31 25" fill="none" class="pb_custom_icon svg-inline--fa pb_icon_kit svg_fw" id="" data="{}" aria="{}" tabindex=""><path d="M14.2031 19.2969L5.20312 10.2969C4.73438 9.875 4.73438 9.17188 5.20312 8.70312C5.625 8.28125 6.32812 8.28125 6.79688 8.70312L15 16.9531L23.2031 8.75C23.625 8.28125 24.3281 8.28125 24.7969 8.75C25.2188 9.17188 25.2188 9.875 24.7969 10.2969L15.75 19.2969C15.3281 19.7656 14.625 19.7656 14.2031 19.2969Z" fill="currentColor"/></svg>' } } </script>
<%= pb_rails("flex", props: {classname: "flex-container", spacing: "between"}) do %> <span> <%= pb_rails("button", props: { text: "Click Inside", variant: "secondary", id: "inside-popover-1" }) %> <%= pb_rails("popover", props: { close_on_click: "inside", trigger_element_id: "inside-popover-1", tooltip_id: "inside-tooltip-1", position: "bottom", offset: true }) do %> Click on me! <% end %> </span> <span> <%= pb_rails("button", props: { text: "Click Outside", variant: "secondary", id: "outside-popover-1" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "outside-popover-1", tooltip_id: "outside-tooltip-1", position: "left", offset: true }) do %> Click anywhere but me! <% end %> </span> <span> <%= pb_rails("button", props: { text: "Click Anywhere", variant: "secondary", id: "any-popover-1" }) %> <%= pb_rails("popover", props: { close_on_click: "any", trigger_element_id: "any-popover-1", tooltip_id: "any-tooltip-1", position: "top", offset: true }) do %> Click anything! <% end %> </span> <% end %>
<div style="position: relative; z-index: 2"> <%= pb_rails("body", props: {text: "I've got a z-index of 2", margin_bottom: "md"}) %> </div> <%= pb_rails("button", props: { variant: "secondary", id: 'tooltip-z-index-1', text: "Click Me", }) %> <%= pb_rails("popover", props: { trigger_element_id: "tooltip-z-index-1", tooltip_id: "tooltip-z-index", position: 'top', z_index: "3", offset: true }) do %> I've got a z-index of 3 <% end %>
<%= pb_rails("button", props: { variant: "secondary", id: 'scroll-height', text: "Click Me" }) %> <%= pb_rails("popover", props: { trigger_element_id: "scroll-height", tooltip_id: "scroll-height-1", position: 'top', close_on_click: "any", max_height: "150px", max_width: "240px", offset: true }) do %> <%= pb_rails("body", props: { margin_bottom: "sm", text: "So many people live within unhappy circumstances and yet will not take the initiative to change their situation because they are conditioned to a life of security, conformity, and conservation, all of which may appear to give one peace of mind, but in reality, nothing is more damaging to the adventurous spirit." }) %> <%= pb_rails("title", props: { size: 4, text: "- Christopher McCandless" }) %> <% end %>
<%= pb_rails("flex", props: { dark: true, orientation: "row", vertical: "center" }) do %> <%= pb_rails("body", props: { text: "Click info for more details" }) %> <%= pb_rails("circle_icon_button", props: { variant: "secondary", icon: "info", id: "actionable-popover-1" }) %> <%= pb_rails("popover", props: { close_on_click: "any", trigger_element_id: "actionable-popover-1", tooltip_id: "actionable-tooltip-1", offset: true, position: "top" }) do %> <%= pb_rails("button", props: { id: "actionable-tooltip-button", text: "Learn more" }) %> <% end %> <% end %> <%= javascript_tag do %> document.addEventListener('DOMContentLoaded', function () { document.querySelector('#actionable-tooltip-button').addEventListener('click', function (e) { alert("Let's do this") }, { once: true }) }) <% end %>
By default, the popover tooltip attaches to the <body>. To attach it elsewhere, use the append_to prop. Set it to "parent" to place the tooltip inside its parent element, or pass any CSS selector (#id or .class) to specify a custom container.
<%= pb_rails("flex", props: { dark: true, orientation: "row", vertical: "center", margin_bottom: "md" }) do %> <%= pb_rails("body", props: { text: "Click info for more details" }) %> <%= pb_rails("circle_icon_button", props: { variant: "secondary", icon: "info", id: "append-to-popover-1" }) %> <%= pb_rails("popover", props: { trigger_element_id: "append-to-popover-1", tooltip_id: "append-to-tooltip-1", offset: true, position: "top", append_to: "parent", }) do %> I'm a popover. I have been appended to my parent element. <% end %> <% end %> <%= pb_rails("flex", props: { dark: true, orientation: "row", vertical: "center" }) do %> <%= pb_rails("body", props: { text: "Click info for more details" }) %> <%= pb_rails("circle_icon_button", props: { variant: "secondary", icon: "info", id: "append-to-popover-2" }) %> <%= pb_rails("popover", props: { trigger_element_id: "append-to-popover-2", tooltip_id: "append-to-tooltip-2", offset: true, position: "top", append_to: ".pb--page--sideNav", }) do %> I'm a popover. I have been appended to the .pb--page--sideNav. <% end %> <% end %>
Use the position prop to control where the popover appears relative to its trigger. Valid values include top, bottom, left, right, and aligned variants such as top-start, top-end, bottom-start, bottom-end, left-start, left-end, right-start, and right-end.
<%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %> <%= pb_rails("button", props: { text: "Top", variant: "secondary", id: "placement-popover-top" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-top", tooltip_id: "placement-tooltip-top", position: "top", offset: true }) do %> Popover: top <% end %> <%= pb_rails("button", props: { text: "Top start", variant: "secondary", id: "placement-popover-top-start" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-top-start", tooltip_id: "placement-tooltip-top-start", position: "top-start", offset: true }) do %> Popover: top start <% end %> <%= pb_rails("button", props: { text: "Top end", variant: "secondary", id: "placement-popover-top-end" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-top-end", tooltip_id: "placement-tooltip-top-end", position: "top-end", offset: true }) do %> Popover: top end <% end %> <% end %> <%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %> <%= pb_rails("button", props: { text: "Bottom", variant: "secondary", id: "placement-popover-bottom" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-bottom", tooltip_id: "placement-tooltip-bottom", position: "bottom", offset: true }) do %> Popover: bottom <% end %> <%= pb_rails("button", props: { text: "Bottom start", variant: "secondary", id: "placement-popover-bottom-start" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-bottom-start", tooltip_id: "placement-tooltip-bottom-start", position: "bottom-start", offset: true }) do %> Popover: bottom start <% end %> <%= pb_rails("button", props: { text: "Bottom end", variant: "secondary", id: "placement-popover-bottom-end" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-bottom-end", tooltip_id: "placement-tooltip-bottom-end", position: "bottom-end", offset: true }) do %> Popover: bottom end <% end %> <% end %> <%= pb_rails("flex", props: { justify: "around", margin_bottom: "sm", orientation: "row", wrap: true }) do %> <%= pb_rails("button", props: { text: "Left", variant: "secondary", id: "placement-popover-left" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-left", tooltip_id: "placement-tooltip-left", position: "left", offset: true }) do %> Popover: left <% end %> <%= pb_rails("button", props: { text: "Left start", variant: "secondary", id: "placement-popover-left-start" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-left-start", tooltip_id: "placement-tooltip-left-start", position: "left-start", offset: true }) do %> Popover: left start <% end %> <%= pb_rails("button", props: { text: "Left end", variant: "secondary", id: "placement-popover-left-end" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-left-end", tooltip_id: "placement-tooltip-left-end", position: "left-end", offset: true }) do %> Popover: left end <% end %> <% end %> <%= pb_rails("flex", props: { justify: "around", orientation: "row", wrap: true }) do %> <%= pb_rails("button", props: { text: "Right", variant: "secondary", id: "placement-popover-right" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-right", tooltip_id: "placement-tooltip-right", position: "right", offset: true }) do %> Popover: right <% end %> <%= pb_rails("button", props: { text: "Right start", variant: "secondary", id: "placement-popover-right-start" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-right-start", tooltip_id: "placement-tooltip-right-start", position: "right-start", offset: true }) do %> Popover: right start <% end %> <%= pb_rails("button", props: { text: "Right end", variant: "secondary", id: "placement-popover-right-end" }) %> <%= pb_rails("popover", props: { close_on_click: "outside", trigger_element_id: "placement-popover-right-end", tooltip_id: "placement-tooltip-right-end", position: "right-end", offset: true }) do %> Popover: right end <% end %> <% end %>
<%= pb_rails("flex", props: { gap: "md", wrap: true }) do %> <%= pb_rails("flex/flex_item") do %> <span id='regular-tooltip-1'>Hover here (Top)</span> <%= pb_rails("tooltip", props: { trigger_element_selector: "#regular-tooltip-1", tooltip_id: "tooltip-1", position: 'top' }) do %> Whoa. I'm a tooltip. <% end %> <% end %> <%= pb_rails("flex/flex_item") do %> <span id='regular-tooltip-2'>Hover here (Bottom)</span> <%= pb_rails("tooltip", props: { trigger_element_selector: "#regular-tooltip-2", tooltip_id: "tooltip-2", position: 'bottom' }) do %> Whoa. I'm a tooltip. <% end %> <% end %> <%= pb_rails("flex/flex_item") do %> <span id='regular-tooltip-3'>Hover here (Right)</span> <%= pb_rails("tooltip", props: { trigger_element_selector: "#regular-tooltip-3", tooltip_id: "tooltip-3", position: 'right' }) do %> Whoa. I'm a tooltip. <% end %> <% end %> <%= pb_rails("flex/flex_item") do %> <span id='regular-tooltip-4'>Hover here (Left)</span> <%= pb_rails("tooltip", props: { trigger_element_selector: "#regular-tooltip-4", tooltip_id: "tooltip-4", position: 'left' }) do %> Whoa. I'm a tooltip. <% end %> <% end %> <% end %>
Set the prop interaction as true for cases that require users to copy the content inside the tooltip.
<%= pb_rails("flex", props: { gap: "md", wrap: true }) do %> <%= pb_rails("flex/flex_item") do %> <%= pb_rails("button", props: { text: "With Interaction", id: "tooltip-interaction"}) %> <%= pb_rails("tooltip", props: { trigger_element_selector: "#tooltip-interaction", tooltip_id: "tooltip-with-interaction", position: 'top', interaction: true }) do %> You can copy me <% end %> <% end %> <%= pb_rails("flex/flex_item") do %> <%= pb_rails("button", props: { text: "No Interaction", id: "tooltip-no-interaction"}) %> <%= pb_rails("tooltip", props: { trigger_element_selector: "#tooltip-no-interaction", tooltip_id: "tooltip-without-interaction", position: 'top', }) do %> I'm just a regular tooltip <% end %> <% end %> <% end %>
You can re-use Tooltip by sending trigger_element_selector as a HTML class= attribute.
<%= pb_rails("flex", props: { orientation: "column" }) do %> <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %> <%= pb_rails("button", props: {classname: "tooltip-example-trigger", text: "Example 1"}) %> <% end %> <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %> <%= pb_rails("button", props: {classname: "tooltip-example-trigger", text: "Example 1"}) %> <% end %> <%= pb_rails("tooltip", props: { trigger_element_selector: ".tooltip-example-trigger", tooltip_id: "example-tooltip", position: 'top' }) do %> Whoa. I'm a re-useable tooltip. <% end %> <% end %>
You can customize the height and width of the tooltip's popover.
When using maxHeight, be sure to set a width as well. The text needs to truncate within the width prop.
<%= pb_rails "flex", props: { flex_direction: "row", gap: "md", wrap: true } do %> <%= pb_rails "button", props: { id: "tool-tip-sizing-1", text: "Height and Width" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-sizing-1", tooltip_id: "tool-tip-sizing-1", position: "top", height: "150px", width: "100px" } do %> I'm 150px high and 100px wide! <% end %> <%= pb_rails "button", props: { id: "tool-tip-sizing-2", text: "max_height" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-sizing-2", tooltip_id: "tool-tip-sizing-2", position: "top", width: "250px", max_height: "100px" } do %> I have a max_height of 100px! Lorem ipsum dolor sit amet consectetur adipisicing elit. <% end %> <%= pb_rails "button", props: { id: "tool-tip-sizing-3", text: "max_width" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-sizing-3", tooltip_id: "tool-tip-sizing-3", position: "top", max_width: "150px" } do %> I have a max_width of 150px! Lorem ipsum dolor sit amet consectetur adipisicing elit. <% end %> <%= pb_rails "button", props: { id: "tool-tip-sizing-4", text: "min_width" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-sizing-4", tooltip_id: "tool-tip-sizing-4", position: "top", min_width: "300px" } do %> I have a min_width of 300px! <% end %> <%= pb_rails "button", props: { id: "tool-tip-sizing-5", text: "min_height" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-sizing-5", tooltip_id: "tool-tip-sizing-5", position: "top", min_height: "300px", height: "200px" } do %> I have a min_height of 300px! <% end %> <% end %>
<%= pb_rails "flex", props: { flex_direction: "row", gap: "md", wrap: true } do %> <%= pb_rails "button", props: { id: "tool-tip-with-icon-1", text: "Tooltip With Icon" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-with-icon-1", tooltip_id: "tool-tip-with-icon-1", position: "top" } do %> <%= pb_rails("icon", props: { icon: "paper-plane", fixed_width: true, color: "white", size: "1x", padding_right: "xxs" }) %> Send Email <% end %> <%= pb_rails "button", props: { id: "tool-tip-with-icon-2", text: "Tooltip With Icon" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-with-icon-2", tooltip_id: "tool-tip-with-icon-2", position: "bottom" } do %> <%= pb_rails("icon", props: { icon: "paper-plane", fixed_width: true, color: "white", size: "1x", padding_right: "xxs" }) %> Send Email <% end %> <%= pb_rails "button", props: { id: "tool-tip-with-icon-3", text: "Tooltip With Icon" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-with-icon-3", tooltip_id: "tool-tip-with-icon-3", position: "left" } do %> <%= pb_rails("icon", props: { icon: "paper-plane", fixed_width: true, color: "white", size: "1x", padding_right: "xxs" }) %> Send Email <% end %> <%= pb_rails "button", props: { id: "tool-tip-with-icon-4", text: "Tooltip With Icon" } %> <%= pb_rails "tooltip", props: { trigger_element_selector: "#tool-tip-with-icon-4", tooltip_id: "tool-tip-with-icon-4", position: "right" } do %> <%= pb_rails("icon", props: { icon: "paper-plane", fixed_width: true, color: "white", size: "1x", padding_right: "xxs" }) %> Send Email <% end %> <% end %>
Waits for the specified time when the event listener runs before triggering the tooltip.
The delay_open and delay_close accept numbers in milliseconds. 1 second is 1000 milliseconds.
<%= pb_rails("flex", props: { orientation: "row", gap: "md" }) do %> <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %> <%= pb_rails("button", props: {classname: "tooltip-delay", text: "1s delay"}) %> <% end %> <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %> <%= pb_rails("button", props: {classname: "tooltip-open-delay", text: "Open only"}) %> <% end %> <%= pb_rails("flex/flex_item", props: {margin_top: "md"}) do %> <%= pb_rails("button", props: {classname: "tooltip-close-delay", text: "Close only"}) %> <% end %> <%= pb_rails("tooltip", props: { trigger_element_selector: ".tooltip-delay", tooltip_id: "delay-tooltip", position: 'top', delay_open: 1000, delay_close: 1000 }) do %> 1s open/close delay <% end %> <%= pb_rails("tooltip", props: { trigger_element_selector: ".tooltip-open-delay", tooltip_id: "open-tooltip", position: 'top', delay_open: 1000 }) do %> 1s open delay <% end %> <%= pb_rails("tooltip", props: { trigger_element_selector: ".tooltip-close-delay", tooltip_id: "close-tooltip", position: 'top', delay_close: 1000 }) do %> 1s close delay <% end %> <% end %>
enabled
You can build your own logic to control whether to show or hide the tooltip.
Click on the Toggle state button to change the state of the component and hover over the 'hover me' text to see it in action.
Each Tooltip has a dataset with the pbTooltipShowTooltip property set to true by default. To update it, access the pbTooltipShowTooltip in the dataset of your tooltip element: yourTooltip.dataset.pbTooltipShowTooltip = 'false'
<%= pb_rails("flex", props: { orientation: "column", gap: "md" }) do %> <%= pb_rails("button", props: {text: "Toggle state", id: "toggle-tooltip-button"}) %> <%= pb_rails("body") do %> Tooltip is: <code id="show-tooltip-state">enabled</code> <% end %> <%= pb_rails("flex/flex_item") do %> <span id="truncated-tooltip-1">Hover me</span> <%= pb_rails("tooltip", props: { trigger_element_selector: "#truncated-tooltip-1", tooltip_id: "truncated-1", position: "right", }) do %> Tooltip is enabled <% end %> <% end %> <% end %> <script> const toggleTooltipButton = document.getElementById("toggle-tooltip-button"); const showTooltipStateText = document.getElementById("show-tooltip-state"); function hideTooltipIfNotTruncated(tooltipId) { const tooltipElement = document.querySelector( `[data-pb-tooltip-tooltip-id="${tooltipId}"]` ); tooltipElement.dataset.pbTooltipShowTooltip = tooltipElement.dataset.pbTooltipShowTooltip == "false" ? "true" : "false"; showTooltipStateText.innerText = tooltipElement.dataset.pbTooltipShowTooltip == "false" ? "disabled" : "enabled"; } toggleTooltipButton.addEventListener("click", () => { hideTooltipIfNotTruncated("truncated-1"); }); </script>
Set the prop use_click_to_open as true so that the tooltip will only appear when an item is clicked rather than hovered over.
<%= pb_rails("button", props: { text: "Click to Open", id: "click-tooltip-trigger-1", variant: "primary" }) %> <%= pb_rails("tooltip", props: { trigger_element_selector: "#click-tooltip-trigger-1", tooltip_id: "click-tooltip-1", position: "top", use_click_to_open: true }) do %> Tooltip opened by click! Click trigger again to close. <% end %>