# Dialog

Display content in a modal dialog, on top of the page content.

# Config

The options below are to be set in the global configuration at the following location:

{
    components: {
        dialog: {
            // ...
        },
    }
}

# class

Classes applied to the component dialog element, except when the prop bare is set to true. See styling components.

  • type: Array<String | Object> | Object | String | (props: Object) => {}
  • default: null

# Example

class({ variant }) {
    return ['dialog', {
        'dialog--large': variant?.includes('large'),
        'dialog--fullscreen': variant?.includes('fullscreen'),
    }]
}

# overlayClass

Classes applied to the component overlay element, except when the prop bare is set to true. See styling components.

The overlay is the element that contains the dialog, it’s usually covering the screen and clicking on it closes the dialog.

  • type: Array<String | Object> | Object | String | (props: Object) => {}
  • default: null

# Example

class: 'dialog-overlay'

# transition

Apply a common transition to all Dialogs. The object can contain any Vue built-in transition component props (opens new window).

  • type: object
  • default: null

# Example

{ name: 'fade', mode: 'out-in' }

# API

CDialog

Name Type Default Description
Props
variant  string|array null

Useful when used in the component config class option, to style it conditionally. See styling components.

bare  boolean false

Disable class inheritance from the component config. See styling components.

transition  BaseTransitionProps | false null

The object can contain any Vue built-in transition component props.

For example: { name: "fade", mode: "out-in" }.

If you defined a default transition in the config and want to disable it, use false.

modelValue * boolean

Define if the dialog should be visible or not

overlay  Record<string, unknown> () => ({})

Attributes to be applied to the overlay element.

For example: { class: 'custom-overlay', id: 'gallery-modal' }

Events
update:modelValue

# Behavior

Dialogs are rendered in a “portal” at the end of the document body element, within an element having the id chusho-dialogs-portal. If you don’t include this element on your own, it will be created automatically. All the sibling elements of this container will get an aria-hidden attribute set to true when the dialog is open and removed when it’s closed. This ensure screen readers focus on the dialog content and ignore the rest while it’s open.

Example of what the DOM structure should look like when a dialog is open:

<body>
    <!-- Ignored by screen readers with the `aria-hidden` attribute -->
    <div id="app" aria-hidden="true">
        <!-- Content of the page -->
    </div>

    <div id="chusho-dialogs-portal">
        <!-- Dialogs currently open -->
    </div>
</body>

For the same reason, the keyboard focus is trapped within the dialog. Consequently using Tab (with or without Shift) will loop only on focusable elements present within the Dialog, all other elements are ignored.

Once open, a dialog can be closed with the ESC key, by clicking on its overlay (the area around the dialog itself), or any custom button that changes the v-model variable to false. It does not include a close button by default, so you’re free to position it and style it any way you want. However it’s highly recommended you add one with a proper label.

Here’s an example using a button with just a “close” icon. As you can see we provide an alternate text for the icon so it stays accessible for everyone.

<CBtn @click="dialogOpen = false">
    <CIcon id="close" alt="Close dialog" />
</CBtn>

# Examples

# Simplest

<script>
export default {
    data() {
        return {
            dialogOpen: false,
        };
    },
};
</script>

<template>
    <CBtn @click="dialogOpen = true">Open Dialog</CBtn>

    <CDialog v-model="dialogOpen">Dialog Content</CDialog>
</template>

# With transition

Here’s an example where the transition is directly passed as a prop. You can also define it globally for all your dialogs; see the config.

<script>
export default {
    data() {
        return {
            dialogOpen: false,
        };
    },
};
</script>

<template>
    <CBtn @click="dialogOpen = true">Open Dialog</CBtn>

    <CDialog v-model="dialogOpen" :transition="{ name: 'dialog' }">
        <div>Dialog Content</div>

        <CBtn @click="dialogOpen = false">Close Dialog</CBtn>
    </CDialog>
</template>

This example use the following style to have a different transition between the overlay and the dialog:

.dialog-enter-active,
.dialog-leave-active {
    transition: opacity 0.2s;

    .dialog {
        transition-duration: 0.3s;
        transition-property: opacity transform;
        transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.4);
    }
}

.dialog-enter-from,
.dialog-leave-to {
    opacity: 0;

    .dialog {
        opacity: 0;
        transform: scale(0.9);
    }
}

TIP

In the example above, we added an aria-labelledby attribute on the CDialog component that reference the id of the h1 within the Dialog. This is a great accessibility practice to give more context to your dialog.