Dialog
A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
Usage
Example
RubyUI to the rescue
RubyUI helps you build accessible standard compliant web apps with ease
Dialog do DialogTrigger do Button { "Open Dialog" } end DialogContent do DialogHeader do DialogTitle { "RubyUI to the rescue" } DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" } end DialogMiddle do AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do img( alt: "Placeholder", loading: "lazy", src: helpers.image_path("pattern.jpg") ) end end DialogFooter do Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" } Button { "Save" } end end end
Size
Applicable for wider screens
RubyUI to the rescue
RubyUI helps you build accessible standard compliant web apps with ease
RubyUI to the rescue
RubyUI helps you build accessible standard compliant web apps with ease
div(class: 'flex flex-wrap justify-center gap-2') do Dialog do DialogTrigger do Button { "Small Dialog" } end DialogContent(size: :sm) do DialogHeader do DialogTitle { "RubyUI to the rescue" } DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" } end DialogMiddle do AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do img( alt: "Placeholder", loading: "lazy", src: helpers.image_path("pattern.jpg") ) end end DialogFooter do Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" } Button { "Save" } end end end Dialog do DialogTrigger do Button { "Large Dialog" } end DialogContent(size: :lg) do DialogHeader do DialogTitle { "RubyUI to the rescue" } DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" } end DialogMiddle do AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do img( alt: "Placeholder", loading: "lazy", src: helpers.image_path("pattern.jpg") ) end end DialogFooter do Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" } Button { "Save" } end end end end
Installation
Using RubyUI CLI
Run the install command
rails g ruby_ui:component Dialog
Manual installation
1
Add RubyUI::Dialog
to app/components/ruby_ui/dialog.rb
# frozen_string_literal: true module RubyUI class Dialog < Base def initialize(open: false, **attrs) @open = open super(**attrs) end def view_template(&) div(**attrs, &) end private def default_attrs { data: { controller: "ruby-ui--dialog", ruby_ui__dialog_open_value: @open } } end end end
2
Add RubyUI::DialogContent
to app/components/ruby_ui/dialog/dialog_content.rb
# frozen_string_literal: true module RubyUI class DialogContent < Base SIZES = { xs: "max-w-sm", sm: "max-w-md", md: "max-w-lg", lg: "max-w-2xl", xl: "max-w-4xl", full: "max-w-full" } def initialize(size: :md, **attrs) @size = size super(**attrs) end def view_template template(data: {ruby_ui__dialog_target: "content"}) do div(data_controller: "ruby-ui--dialog") do backdrop div(**attrs) do yield close_button end end end end private def default_attrs { data_state: "open", class: [ "fixed pointer-events-auto left-[50%] top-[50%] z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full", SIZES[@size] ] } end def close_button button( type: "button", class: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", data_action: "click->ruby-ui--dialog#dismiss" ) do svg( width: "15", height: "15", viewbox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: "h-4 w-4" ) do |s| s.path( d: "M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z", fill: "currentColor", fill_rule: "evenodd", clip_rule: "evenodd" ) end span(class: "sr-only") { "Close" } end end def backdrop div( data_state: "open", data_action: "click->ruby-ui--dialog#dismiss esc->ruby-ui--dialog#dismiss", class: "fixed pointer-events-auto inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" ) end end end
3
Add RubyUI::DialogDescription
to app/components/ruby_ui/dialog/dialog_description.rb
# frozen_string_literal: true module RubyUI class DialogDescription < Base def view_template(&) p(**attrs, &) end private def default_attrs { class: "text-sm text-muted-foreground" } end end end
4
Add RubyUI::DialogFooter
to app/components/ruby_ui/dialog/dialog_footer.rb
# frozen_string_literal: true module RubyUI class DialogFooter < Base def view_template(&) div(**attrs, &) end private def default_attrs { class: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 gap-y-2 sm:gap-y-0" } end end end
5
Add RubyUI::DialogHeader
to app/components/ruby_ui/dialog/dialog_header.rb
# frozen_string_literal: true module RubyUI class DialogHeader < Base def view_template(&) div(**attrs, &) end private def default_attrs { class: "flex flex-col space-y-1.5 text-center sm:text-left" } end end end
6
Add RubyUI::DialogMiddle
to app/components/ruby_ui/dialog/dialog_middle.rb
# frozen_string_literal: true module RubyUI class DialogMiddle < Base def view_template(&) div(**attrs, &) end private def default_attrs { class: "py-4" } end end end
7
Add RubyUI::DialogTitle
to app/components/ruby_ui/dialog/dialog_title.rb
# frozen_string_literal: true module RubyUI class DialogTitle < Base def view_template(&) h3(**attrs, &) end private def default_attrs { class: "text-lg font-semibold leading-none tracking-tight" } end end end
8
Add RubyUI::DialogTrigger
to app/components/ruby_ui/dialog/dialog_trigger.rb
# frozen_string_literal: true module RubyUI class DialogTrigger < Base def view_template(&) div(**attrs, &) end private def default_attrs { data: { action: "click->ruby-ui--dialog#open" }, class: "inline-block" } end end end
9
Add dialog_controller.js
to app/javascript/controllers/ruby_ui/dialog_controller.js
import { Controller } from "@hotwired/stimulus" // Connects to data-controller="dialog" export default class extends Controller { static targets = ["content"] static values = { open: { type: Boolean, default: false }, } connect() { if (this.openValue) { this.open() } } open(e) { e.preventDefault() document.body.insertAdjacentHTML('beforeend', this.contentTarget.innerHTML) // prevent scroll on body document.body.classList.add('overflow-hidden') } dismiss() { // allow scroll on body document.body.classList.remove('overflow-hidden') // remove the element this.element.remove() } }
10
Update the Stimulus controllers manifest file
Importmap!
rake stimulus:manifest:update
Components
Component | Built using | Source |
---|---|---|
Dialog | Phlex | |
DialogContent | Phlex | |
DialogDescription | Phlex | |
DialogFooter | Phlex | |
DialogHeader | Phlex | |
DialogMiddle | Phlex | |
DialogTitle | Phlex | |
DialogTrigger | Phlex | |
DialogController | Stimulus JS |