Dialog
<template>
<PeachyDialog.Dialog>
<PeachyDialog.Trigger>Open</PeachyDialog.Trigger>
<Teleport to="body">
<PeachyDialog.Target>
<PeachyDialog.Close aria-label="Close">
<CrossSvg />
</PeachyDialog.Close>
<PeachyDialog.Title>Title</PeachyDialog.Title>
<PeachyDialog.Description>Description</PeachyDialog.Description>
Content
</PeachyDialog.Target>
</Teleport>
</PeachyDialog.Dialog>
</template>
.peachy-dialog__target[open]:not(.date-picker-dialog) {
border: none;
width: 18rem;
padding: 1rem 2rem 2rem 2rem;
border-radius: var(--border-radius);
background: var(--bg);
box-shadow: var(--shadow);
}
.peachy-dialog__target:focus-visible {
outline-offset: 0;
}
.peachy-dialog__target[open]:not(.date-picker-dialog)::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
.peachy-dialog__title {
font-size: 120%;
font-weight: var(--fw-bold);
margin-bottom: 0.25rem;
}
.peachy-dialog__description {
margin-bottom: 1rem;
color: var(--dimmed-text);
}
.peachy-dialog__close {
cursor: pointer;
position: absolute;
top: 1rem;
right: 1rem;
display: grid;
place-content: center;
border-radius: 100%;
padding: var(--icon-button-padding);
transition: background 0.25s;
}
.peachy-dialog__close:hover {
background: var(--button-hover-bg);
}
.peachy-dialog__close svg {
width: var(--icon-size);
}
/* ===== Animation ===== */
@media (prefers-reduced-motion: no-preference) {
.peachy-dialog__target[open]:not(.date-picker-dialog) {
animation: ScaleIn 0.25s;
}
.peachy-dialog__target[open]:not(.date-picker-dialog)::backdrop {
animation: FadeIn 0.25s;
}
}
@keyframes ScaleIn {
from {
transform: scale(0.75);
}
to {
opacity: scale(1);
}
}
@keyframes FadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
Anatomy
<template>
<PeachyDialog.Dialog>
<PeachyDialog.Trigger />
<PeachyDialog.Target>
<PeachyDialog.Title />
<PeachyDialog.Description />
<PeachyDialog.Close />
</PeachyDialog.Target>
</PeachyDialog.Dialog>
</template>
<script lang="ts" setup>
import { PeachyDialog } from "typeach";
</script>
ENSURE KEYBOARD ACCESS
A dialog expects to have at least one focusable element so it can manage focus properly. You can use the autofocus
attribute to decide which element should get first priority.
ENSURE DIALOG CAN CLOSE
If setting modal
to false
, there is no interaction available to close the modal - unless you provide it (with a button or with closeOnOutsideClick
).
Props & Emits
Target
Props
Name | Default | Type | Description |
---|---|---|---|
modal | true | boolean? | |
closeOnOutsideClick | false | boolean? | If modal is false, this requires the dialog's ::backdrop to have a display of none to work. |
placement | Placement? | The placement option for Floating UI. See the Styling section for ensuring proper placement. |
Styling
CSS Selectors
The root component (Dialog
) is purely logical and have no elements to style, otherwise the child components follow our CSS classes convention.
closeOnOutsideClick
AND placement
REQUIRE ADDITIONAL STYLES
- To use
clickOnOutsideClick
whenmodal
is false you need to set the dialog's::backdrop
todisplay: none
. - To use
placement
, set theTarget
's margins to avoid unexpected results due to agent's default styling.
State selectors
Selector | Description | For |
---|---|---|
[data-open="<boolean>"] | For if trigger is open or not. |
|
[open] | For an open dialog. |
|
::backdrop | For the overlay on a modal dialog. |
|
Accessibility
Resources: MDN The Dialog Element, Scott O'Hara's Use the dialog element (reasonably)
ENSURE KEYBOARD ACCESS
A dialog expects to have at least one focusable element so it can manage focus properly. You can use the autofocus
attribute to decide which element should get first priority.
ENSURE DIALOG CAN CLOSE
If setting modal
to false
, there is no interaction available to close the modal - unless you provide it (with a button or with closeOnOutsideClick
).
Follows the keyboard interactions provided by the native dialog element.