See CModal
's accessibility report
Modal
A dialog is a window overlaid on either the primary window or another dialog window. Contents behind a modal dialog are inert meaning that users cannot interact with content behind the dialog.
Import#
Chakra exports eight components to help you create any modal dialog.
CModal
: The wrapper that provides context for its childrenCModalOverlay
: The dimmed overlay behind the modal dialogCModalContent
: The container for the modal dialog's contentCModalHeader
: The header that labels the modal dialogCModalFooter
: The footer that houses the modal actionsCModalBody
: The wrapper that houses the modal's main contentCModalCloseButton
: The button that closes the modal.
import {
CModal,
CModalOverlay,
CModalContent,
CModalHeader,
CModalFooter,
CModalBody,
CModalCloseButton,
} from "@chakra-ui/vue";
Usage#
When the modal opens, focus is sent into the modal and set to the first tabbable
element. If there are no tabbable elements, focus is set on the CModalContent
.
<template>
<div>
<c-button left-icon="check" mb="3" variant-color="blue" @click="open" variant="outline">Open Modal</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
>
<c-modal-content ref="content">
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<Lorem add="2s" />
</c-modal-body>
<c-modal-footer>
<c-button variant-color="blue" mr="3">
Save
</c-button>
<c-button @click="close">Cancel</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Block Scrolling when Modal opens#
For accessibility, it's recommended to block scrolling on the main document
behind the modal. Chakra does this by default but you can set
blockScrollOnMount
to false
to allow scrolling behind modal.
<template>
<div>
<c-button left-icon="check" mb="3" variant-color="blue" @click="open" variant="outline">Open Modal</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
:block-scroll-on-mount="blockScrollOnMount"
>
<c-modal-content ref="content">
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
You can scroll the content behind the modal
</c-modal-body>
<c-modal-footer>
<c-button variant-color="blue" mr="3">
Close
</c-button>
<c-button @click="close">Secondary Action</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false,
blockScrollOnMount: false
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Focus on a specific element#
Chakra automatically sets focus on the first tabbable element in the modal. However, there might be scenarios where you need to manually control where focus goes.
Chakra provides two props for this use-case:
initialFocusRef
: Accepts a$ref
or a function that returns the$ref
of the component that receives focus when the modal opens.finalFocusRef
: Accepts a$ref
or a function that returns the$ref
of the component that receives focus when the modal closes.
If you set
finalFocusRef
, internally we setreturnFocusOnClose
tofalse
so it doesn't return focus to the element that triggered it.
<template>
<div>
<c-button mr="3" @click="open">Open Modal</c-button>
<c-button ref="finalRef">
I'll receive focus on close
</c-button>
<c-modal
:initial-focus-ref="() => $refs.initialRef"
:final-focus-ref="() => $refs.finalRef"
:is-open="isOpen"
:on-close="close"
>
<c-modal-content ref="content">
<c-modal-header>Create your account</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<c-form-control>
<c-form-label>First name</c-form-label>
<c-input ref="initialRef" placeholder="First name" />
</c-form-control>
<c-form-control mt="4">
<c-form-label>Last name</c-form-label>
<c-input placeholder="Last name" />
</c-form-control>
</c-modal-body>
<c-modal-footer>
<c-button variant-color="blue" mr="3">
Cancel
</c-button>
<c-button @click="close">Save</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Close Modal on Overlay Click#
By default, the modal closes when you click its overlay. You can set
closeOnOverlayClick
to false
if you want the modal to stay visible.
<template>
<div>
<c-button variant-color="blue" @click="open">Open Modal</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
:closeOnOverlayClick="false"
>
<c-modal-content ref="content">
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<Lorem add="2s" />
</c-modal-body>
<c-modal-footer>
<c-button variant-color="blue" mr="3">
Save
</c-button>
<c-button @click="close">Cancel</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Make modal vertically centered#
By default, the modal has a vertical offset of 3.75rem
which you can change by
passing top
to the CModalContent
. If you need to vertically center the modal,
pass the isCentered
If the content within the modal overflows beyond the viewport, don't use this prop. Try setting the overflow behavior instead
<template>
<div>
<c-button variant-color="blue" @click="open">Open Modal</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
:closeOnOverlayClick="false"
is-centered
>
<c-modal-content ref="content">
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<Lorem add="2s" />
</c-modal-body>
<c-modal-footer>
<c-button @click="close">Cancel</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Modal overflow behavior#
If the content within the modal overflows beyond the viewport, you can use the
scrollBehavior
to control how scrolling should happen.
- If set to
inside
, scroll only occurs within theModalBody
. - If set to
outside
, the entireModalContent
will scroll within the viewport.
<template>
<div>
<c-radio-group
isInline
v-model="scrollBehavior"
>
<c-radio value="inside">inside</c-radio>
<c-radio value="outside">outside</c-radio>
</c-radio-group>
<c-button variant-color="blue" @click="open">Open Modal</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
:closeOnOverlayClick="false"
:scroll-behavior="scrollBehavior"
is-centered
>
<c-modal-content ref="content" >
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<div>
<lorem add="5p" />
</div>
</c-modal-body>
<c-modal-footer>
<c-button @click="close">Cancel</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false,
scrollBehavior: 'inside'
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
}
}
}
</script>
Modal Sizes#
Pass the size
prop if you need to adjust the size of the modal. Values can be
xs
, sm
, md
, lg
, xl
, or full
.
<template>
<div>
<c-button v-for="(size, i) in sizes" m="4" :key="i" @click="openSizedModal(size)">
Open {{ size }} Modal
</c-button>
<c-modal
:is-open="isOpen"
:on-close="close"
:closeOnOverlayClick="false"
:size="size"
is-centered
>
<c-modal-content ref="content">
<c-modal-header>Modal Title</c-modal-header>
<c-modal-close-button />
<c-modal-body>
<div>
<lorem add="5s" />
</div>
</c-modal-body>
<c-modal-footer>
<c-button @click="close">Cancel</c-button>
</c-modal-footer>
</c-modal-content>
<c-modal-overlay />
</c-modal>
</div>
</template>
<script>
export default {
data () {
return {
isOpen: false,
sizes: ['xs', 'sm', 'md', 'lg', 'xl', 'full'],
size: 'xs'
}
},
methods: {
open() {
this.isOpen = true
},
close() {
this.isOpen = false
},
openSizedModal(size) {
this.size = size
this.open()
}
}
}
</script>
Making other elements Inert#
When the CModal
is open, it's rendered within a portal and all its siblings have
aria-hidden
set to true
so the only thing screen readers see is the modal.
Accessibility#
Keyboard and Focus Management#
- When the modal opens, focus is trapped within it.
- When the dialog opens, focus is automatically set to the first enabled
element, or the element with the
initialFocusRef
. - When the modal closes, focus returns to the element that was focused right
before the modal activated, or the element with the
finalFocusRef
- Clicking on the overlay closes the Modal.
- Pressing Esc closes the Modal.
- Scrolling is blocked on the elements behind the modal.
- The modal is portalled to the end of
document.body
to break it out of the source order and make it possible to addaria-hidden
to its siblings.
ARIA attributes#
- The
CModalContent
hasaria-modal
set totrue
. - The
CModalContent
hasaria-labelledby
set to theid
of theCModalHeader
- The
CModalContent
hasaria-describedby
set to theid
of theCModalBody
Props
CModal
#
CModal
#Props#
Name | Type | Default | Description |
---|---|---|---|
isOpen | boolean | If true , the modal will open | |
isCentered | boolean | If true , the Modal will be centered on screen | |
initialFocusRef | vm.$ref , () => vm.ref or CSS selector | The ref of the element to receive focus when the dialog opens | |
finalFocusRef | vm.$ref , () => vm.ref or CSS selector | The ref of element to receive focus when the dialog closes | |
blockScrollOnMount | boolean | true | If true , scrolling will be disabled on the body when the modal opens. |
preserveScrollBarGap | boolean | If true , a padding-right will be applied to the body element to preserve the scrollbar gap. | |
useInert | boolean | true | A11y: If true , all elements behing the Modal will have aria-hidden set to true so that screen readers can only see the Modal . |
size | $chakraTheme.sizes | md | The size (maxWidth) of the modal. |
scrollBehavior | inside , outside | outside | Where scroll behaviour should originate. |
closeOnOverlayClick | boolean | true | If true , the modal will close when the overlay is clicked |
returnFocusOnClose | boolean | true | If true , the modal will return focus to the element that triggered it when it closes. |
closeOnEsc | boolean | true | If true , the modal will close when the Esc key is pressed |
addAriaLabels | boolean , {header: boolean, body: boolean} | true | If false , no aria-* properties will be added by default. |
id | string | The id of the modal |
Events#
Name | Payload | Description |
---|---|---|
@close | - | The event emitted when the CModalCloseButton is clicked. |
Slots#
Name | Description |
---|---|
default | Slot for CModal components |
Other components#
CModalOverlay
,CModalHeader
,CModalFooter
andCModalBody
compose theCBox
component.CModalCloseButton
composesCCloseButton
❤️ Contribute to this page
Caught a mistake or want to contribute to the documentation? Edit this page on GitHub!