Skip to content

renatodeleao/a11y-vue-dialog

Repository files navigation

Why another modal/dialog plugin

  • ✅ Universal: works in vue@2 and vue@3 🚧
  • ✅ Renderless/headless: no assumptions about styles or markup. You have full control.
  • ✅ Accessibility first — Focus trap[1] + keyboard navigation + aria-attributes
  • ✅ Fully controlled component
  • ✅ Pure vue, no wrapping.
  • ✅ Simplicity + size
  • 🕸 Nested dialogs (questionable pattern, not recommended, but possible because it happens) and it's actually in WAI-ARIA examples so...

Detailed documentation and additional info is available at documentation site

Install

npm i a11y-vue-dialog

# or

yarn add a11y-dialog 

Usage

A renderless/headless component provides all the functionality required to build a proper Dialog, but gives zero f*cks about your styles. As such you have full control over it and have to DYI. Here's a basic example on how to do it:

<!-- AppBaseDialog.vue -->
<template>
  <a11y-dialog 
    v-bind="$attrs" 
    v-on="$listeners"
    v-slot:default="{ rootRef, dialogRef, titleRef, closeRef }"
  > 
    <div v-bind="rootRef.prop">
      <!-- Bindings do the accessibility attributes for you -->
      <div v-bind="dialogRef.props" v-on="dialogRef.listeners">
        <h1 v-bind="titleRef.props">{{ title }}</h1>
        <button v-bind="closeRef.props" v-on="closeRef.listeners">
      </div>
    </div>
    ...
    <slot />
  </a11y-dialog>
</template>

<script>
import { A11yDialog } from 'a11y-dialog'

export default {
  name: 'AppBaseDialog',
  components: { A11yDialog },
  props: {
    title: {
      type: String,
      required: true
    }
  }
}
</script>
<!-- At any View.vue, after import AppBaseDialog -->
<template>
  <div id="page">
    <button @click="isDialogOpen = true">
    <app-base-dialog
      title="Hello world"
      :open="isDialogOpen" 
      @close="openMyModal = false" 
      @confirm="handSubmit"
    >
      My markup, my rules.
    </app-base-dialog>
  </div>
</template>

Voilá, checkout a working example on CodeSandbox.

Docs

Detailed documentation and additional info is available at documentation site

Play

A playground is used to test the component locally. It uses vue/cli instant prototyping feature, so the downside is that you have to install it globally.

  • Clone this repo
  • yarn install
  • Then, just run yarn play

Colophon

Thanks to all this packages for inspiration and guidance.

  • portal-vue|vue-simple-portal from @LinusBorg which makes escaping overflow traps easy peasy
  • a11y-dialog (vanilla) from @KittyGiraudel to lead the path that ended here
  • vue-a11y-dialog (wrapper around ^) from @morkro for the motivation to build a pure vue alternative to it.
  • All build tools used to make this a reality!

License

MIT © Renato de Leão