Skip to content

Dialog


vue
<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>
css
.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

vue
<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

NameDefaultTypeDescription
modaltrueboolean?
closeOnOutsideClickfalseboolean?If modal is false, this requires the dialog's ::backdrop to have a display of none to work.
placementPlacement?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 when modal is false you need to set the dialog's ::backdrop to display: none.
  • To use placement, set the Target's margins to avoid unexpected results due to agent's default styling.

State selectors

SelectorDescriptionFor
[data-open="<boolean>"]For if trigger is open or not.
  • Trigger
[open]For an open dialog.
  • Target
::backdropFor the overlay on a modal dialog.
  • Target

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.