Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UI ARC Radiant Components
v4.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Dialog

General-purpose focus-trapping overlay on the platform <dialog> — backdrop blur, slide-up entrance, and Escape-to-dismiss for forms, settings, and rich content that needs full user attention.

Components Dialog
feedback interactive
<arc-dialog>

Overview

Dialog is the general-purpose overlay primitive, built on the platform's native `<dialog>` element. It floats above the page behind a blurred backdrop, moves focus inside on open, and returns focus to the trigger element on close. Use it any time you need a rich container for forms, settings panels, content previews, or multi-step workflows where background interaction must be blocked — the native top layer and `::backdrop` do the heavy lifting the way the platform intends. **Renamed in v4.** This component was `arc-modal` through v3; the element is a dialog, the platform calls it a dialog, and *modal* named one of its behaviours rather than what it is. The old tag is gone in v4.0.0 — removed rather than aliased, since v4 never shipped and an alias would have served nobody. Note the hazard in the other direction: the v3 tag `arc-dialog` was a small confirm prompt, and that component is now `arc-confirm`. Handing this Dialog the old prompt props (`message`, `confirm-label`, `cancel-label`) logs a `console.error` naming `arc-confirm` rather than silently ignoring them. The component ships with three width presets (`sm`/`md`/`lg`), a `fullscreen` mode, and a smooth slide-up entrance. Dismissal is governed by one prop: `dismissible` renders the built-in close button and enables Escape and backdrop click, and it defaults to on — a dialog is dismissible unless you say otherwise. Set it to `false` for decisions the user must resolve through the footer buttons. The `arc-close` event is cancelable, so `preventDefault()` can veto a close while a form inside is mid-save.

Guidelines

When to use

  • Use Dialog for rich content that blocks the page: edit forms, creation wizards, detail views, settings panels
  • Keep `dismissible` on unless abandoning the dialog would lose meaningful user state
  • Put primary actions in the `footer` slot, with the confirming action last
  • Use `size="sm"` for short single-purpose dialogs and `lg` only for genuinely dense content
  • Cancel the `arc-close` event to hold the dialog open while an in-flight save completes

When not to use

  • Do not use Dialog for a yes/no prompt — that is `arc-confirm`, which exists so you never rebuild the two-button layout
  • Do not stack dialogs — resolve one before opening another
  • Do not use Dialog for passive notifications — use Alert or Toast, which do not steal focus
  • Do not disable `dismissible` for convenience; an inescapable overlay must be earning that severity

Features

  • Built on the native `<dialog>` element — top layer, `::backdrop`, and modality from the platform
  • Automatic focus trap — focus moves inside on open and returns to the trigger on close
  • Backdrop blur and dim, styled via `--dialog-backdrop` and `--dialog-backdrop-filter`
  • Slide-up entry and fade-out exit animations
  • `dismissible` (default on): built-in close button, Escape key, and backdrop click
  • Cancelable `arc-close` event — `preventDefault()` vetoes the close
  • Three width presets: sm (400px), md (560px), lg (720px), plus `fullscreen`
  • `header` and `footer` slots around arbitrary body content
  • `heading` doubles as the dialog’s accessible name

Preview

Edit Profile
Cancel Save Changes

Usage

This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.

<arc-button id="edit">Edit Profile</arc-button>

<arc-dialog heading="Edit Profile" size="sm">
  <arc-input label="Display Name"></arc-input>
  <div slot="footer">
    <arc-button variant="ghost" data-close>Cancel</arc-button>
    <arc-button variant="primary" data-close>Save Changes</arc-button>
  </div>
</arc-dialog>

<script>
  const dialog = document.querySelector('arc-dialog');
  document.getElementById('edit').addEventListener('click', () => {
    dialog.open = true;
  });
  dialog.addEventListener('click', (e) => {
    if (e.target.closest('[data-close]')) dialog.open = false;
  });
</script>
import { Dialog, Button, Input } from '@arclux/arc-ui-react';
import { useState } from 'react';

function EditProfile() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Edit Profile</Button>
      <Dialog heading="Edit Profile" size="sm" open={open} onArcClose={() => setOpen(false)}>
        <Input label="Display Name" />
        <div slot="footer">
          <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
          <Button variant="primary" onClick={() => setOpen(false)}>Save Changes</Button>
        </div>
      </Dialog>
    </>
  );
}
<script setup>
import { ref } from 'vue';
import { Dialog, Button, Input } from '@arclux/arc-ui-vue';

const open = ref(false);
</script>

<template>
  <Button @click="open = true">Edit Profile</Button>
  <Dialog heading="Edit Profile" size="sm" :open="open" @arc-close="open = false">
    <Input label="Display Name" />
    <div slot="footer">
      <Button variant="ghost" @click="open = false">Cancel</Button>
      <Button variant="primary" @click="open = false">Save Changes</Button>
    </div>
  </Dialog>
</template>
<script>
  import { Dialog, Button, Input } from '@arclux/arc-ui-svelte';
  let open = false;
</script>

<Button on:click={() => (open = true)}>Edit Profile</Button>
<Dialog heading="Edit Profile" size="sm" {open} on:arc-close={() => (open = false)}>
  <Input label="Display Name" />
  <div slot="footer">
    <Button variant="ghost" on:click={() => (open = false)}>Cancel</Button>
    <Button variant="primary" on:click={() => (open = false)}>Save Changes</Button>
  </div>
</Dialog>
import { Component } from '@angular/core';
import { Dialog, Button, Input } from '@arclux/arc-ui-angular';

@Component({
  imports: [Dialog, Button, Input],
  template: `
    <arc-button (click)="open = true">Edit Profile</arc-button>
    <arc-dialog heading="Edit Profile" size="sm" [open]="open" (arc-close)="open = false">
      <arc-input label="Display Name" />
      <div slot="footer">
        <arc-button variant="ghost" (click)="open = false">Cancel</arc-button>
        <arc-button variant="primary" (click)="open = false">Save Changes</arc-button>
      </div>
    </arc-dialog>
  `,
})
export class EditProfileComponent {
  open = false;
}
import { Dialog, Button, Input } from '@arclux/arc-ui-solid';
import { createSignal } from 'solid-js';

function EditProfile() {
  const [open, setOpen] = createSignal(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Edit Profile</Button>
      <Dialog heading="Edit Profile" size="sm" open={open()} on:arc-close={() => setOpen(false)}>
        <Input label="Display Name" />
        <div slot="footer">
          <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
          <Button variant="primary" onClick={() => setOpen(false)}>Save Changes</Button>
        </div>
      </Dialog>
    </>
  );
}
import { Dialog, Button, Input } from '@arclux/arc-ui-preact';
import { useState } from 'preact/hooks';

function EditProfile() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Edit Profile</Button>
      <Dialog heading="Edit Profile" size="sm" open={open} onArcClose={() => setOpen(false)}>
        <Input label="Display Name" />
        <div slot="footer">
          <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
          <Button variant="primary" onClick={() => setOpen(false)}>Save Changes</Button>
        </div>
      </Dialog>
    </>
  );
}

API

REUSED_TAG_PROPS array ['message', 'confirmLabel', 'cancelLabel']
The props that belonged to the *old* arc-dialog. V4-SCOPE §3.3 requires this and says why: the old arc-dialog was a confirm prompt with heading, message and confirmLabel, and it merged into arc-confirm. Anyone still writing that markup upgrades into this primitive, which knows heading and would silently ignore the other two — rendering an empty panel with a title. That is the quietest possible failure, and a line in MIGRATION.md is not a fix for it. heading is deliberately not in the list: it means the same thing in both components, so its presence is not evidence of the mistake.
heading string ''
Text displayed in the header bar, and the dialog's accessible name. Keep it short and action-oriented (e.g. "Delete Project" rather than "Are you sure?").
open boolean false
Controls the visible state of the dialog. Set to true to open it and move focus inside; set to false to run the exit animation and restore focus to wherever it came from.
size 'sm' | 'md' | 'lg' 'md'
Controls the maximum width of the dialog panel. sm (400px) is ideal for simple confirmations, md (560px) for standard forms, and lg (720px) for content-heavy dialogs with tables or multi-column layouts.
dismissible boolean true
When true, renders the built-in X close button and allows dismissal via Escape key and backdrop click. Set to false for critical decisions the user must resolve through the footer buttons. Note the default: a dialog is dismissible unless you say otherwise, where an alert is not dismissible unless you say so — the name is the convention, the default belongs to the component.
fullscreen boolean false
Makes the dialog fill the entire viewport. Useful for mobile forms or complex workflows.

Events

arc-close
Fired when the dialog closes. Cancelable: preventDefault() vetoes the close.
arc-open
Fired when the dialog opens

See Also