Skip to content

Dialog

Modal component that uses native HTML5 dialog functionality.

Dialogs are fully controlled by the web platform — opening and closing is handled with native Invoker Commands (command / commandfor) and the closedby attribute, so no JavaScript API is needed.

View Source 

Installation

Follow instructions for individual framework usage below

  • winduum 
  • winduum-vue 
  • winduum-react 

Browser support

The dialog element is Baseline. For older browsers cover Invoker Commands with invokers-polyfill — the closedby attribute is covered by the side-effect script below. See Polyfills.

Styles

Variants

  • default 
  • content 
  • drawer 

Props

  • default 
  • content 

Examples

Basic

html
<button class="x-button" command="show-modal" commandfor="dialogBasic">Show dialog</button>
<dialog class="x-dialog" id="dialogBasic" closedby="any">
    <form class="x-dialog-content" method="dialog">
        <div class="x-heading">Example dialog</div>
        <br>
        <div class="x-text">
            <p>You can close this dialog with Esc, clicking outside, or by form submit</p>
        </div>
        <br>
        <button class="x-button">Close dialog</button>
    </form>
</dialog>
liquid
<button class="x-button" data-controller="x-button" command="show-modal" commandfor="dialogBasic">Show dialog</button>
<dialog class="x-dialog" id="dialogBasic" closedby="any">
    <form class="x-dialog-content" method="dialog">
        <div class="x-heading">Example dialog</div>
        <br>
        <div class="x-text">
            <p>You can close this dialog with Esc, clicking outside, or by form submit</p>
        </div>
        <br>
        <button class="x-button" data-controller="x-button">Close dialog</button>
    </form>
</dialog>
vue
<script setup lang="ts">
    import { useId } from 'vue'
    import { Button } from '@/components/button'
    import { Dialog, DialogContent } from '@/components/dialog'
    import { Heading } from '@/components/heading'

    const dialogBasic = useId()
</script>

<template>
    <Button command="show-modal" :commandfor="dialogBasic">
        Open Dialog
    </Button>
    <Dialog :id="dialogBasic" closedby="any">
        <DialogContent>
            <Heading>Hello there!</Heading>
            <Button class="muted accent-main" command="close" :commandfor="dialogBasic">
                Close me!
            </Button>
        </DialogContent>
    </Dialog>
</template>
tsx
import { useId } from 'react'
import { Button } from '@/components/button'
import { Dialog, DialogContent } from '@/components/dialog'
import { Heading } from '@/components/heading'

export function Example() {
    const dialogBasic = useId()

    return (
        <>
            <Button command="show-modal" commandfor={dialogBasic}>
                Open Dialog
            </Button>
            <Dialog id={dialogBasic}>
                <DialogContent>
                    <Heading>Hello there!</Heading>
                    <Button className="muted accent-main" command="close" commandfor={dialogBasic}>
                        Close me!
                    </Button>
                </DialogContent>
            </Dialog>
        </>
    )
}

Accessibility

The native dialog element provides accessibility out of the box — showModal() moves focus into the dialog, makes the rest of the page inert, closes on Esc and returns focus to the trigger on close. Light-dismiss behavior is controlled declaratively with the closedby attribute.

JavaScript

Always include the dialog side-effect script in every installation variant:

js
import '/src/components/dialog/index.js'

There is no JavaScript API — dialogs use the native HTMLDialogElement interface. If you need to control a dialog programmatically, use the native methods directly

js
document.querySelector('#dialogExample').showModal()
document.querySelector('#dialogExample').close()

The winduum/src/components/dialog side-effect script additionally

  • closes an open dialog when clicking its backdrop, based on the closedby attribute (fallback for browsers without native closedby support)
  • keeps --default-scrollbar-width on <html> updated via a ResizeObserver, which the dialog CSS uses to compensate for the hidden page scrollbar

Released under the MIT License.