Accessible by default
Focus is trapped and restored, Escape and backdrop clicks are wired up, and ARIA roles are set for you. Focus detection skips targets that only look focusable.
Open source · MIT licensed · Zero runtime dependencies
Forge Dialog is a dependency-free TypeScript dialog library built on the
native <dialog> element. Accessible by default, themeable down to
individual components, and small enough that an alert-only bundle stays under 6 KB
gzipped.
npm install forgedialog
Everything below is in the published package — no plugins to install, no peer dependencies to satisfy.
Focus is trapped and restored, Escape and backdrop clicks are wired up, and ARIA roles are set for you. Focus detection skips targets that only look focusable.
Colour and opacity for the surface, title, body, and border. Corner radius per corner. Shadows composed from an angle, distance, blur, and strength.
Opt-in hover restyling with lift and scale. Draggable dialogs with axis locks, bounds, keyboard movement, and persisted positions. Swipe-to-dismiss sheets.
Drawers, bottom sheets, lightboxes, loading states, toasts, a command palette, and persisted branching wizards — all from the same core.
Tree-shakable entry points with enforced gzip budgets. Import
forgedialog/alert and you pay for an alert, not the whole library.
ESM, CJS, and a browser global, with adapters for React, Vue, Svelte, and Web Components. Typed throughout, SSR-safe, and clean under a strict CSP.
Change anything below and the dialog restyles live. The code updates with it — copy it and you have the same dialog in your app.
The everyday calls. Each returns a promise, so there is no callback nesting.
import { alert, confirm, prompt } from 'forgedialog';
import 'forgedialog/style.css';
await alert('Saved successfully.', { title: 'Success' });
const ok = await confirm('Delete this item?');
const name = await prompt('What is your name?', {
validate: (value) => value.trim() ? true : 'Name is required',
});
import { open } from 'forgedialog';
const dialog = open({
title: 'Custom dialog',
content: (container) => container.append(renderForm()),
buttons: [
{ text: 'Cancel', onClick: (i) => i.close(null) },
{ text: 'Save', role: 'primary', onClick: (i) => i.close(read()) },
],
});
const result = await dialog.whenClosed();
// Just an alert, and nothing else.
import { alert } from 'forgedialog/alert';
import 'forgedialog/style/core.css';
// Opt into the richer appearance options on a focused entry.
import 'forgedialog/appearance';
import { drawer, toast, wizard } from 'forgedialog';
// A duration of 0 keeps the toast until dismiss() is called.
const upload = toast('Uploading…', { duration: 0 });
drawer({ title: 'Settings', side: 'right', content: renderSettings });
const data = await wizard({ steps }).result;
The short, factual version — the numbers come from the size budgets enforced on every pull request.
| Name | Forge Dialog |
|---|---|
| npm package | forgedialog |
| License | MIT |
| Runtime dependencies | None |
| Size | ≈15 KB gzipped for the full bundle; ≈5.5 KB for an alert-only build |
| Written in | TypeScript, with types for both ESM and CommonJS |
| Browsers | Chrome/Edge 88+, Firefox 78+, Safari 15.4+ |
| Node.js | 20 or newer, for package tooling and SSR imports |
| Frameworks | Works standalone; adapters for React, Vue, Svelte, and Web Components |
| Source | github.com/cmm-cmm/ForgeDialog |
Forge Dialog is an open-source TypeScript library for building dialogs on the web:
alerts, confirmations, prompts, drawers, bottom sheets, lightboxes, loading states,
toasts, command palettes, and multi-step wizards. It is published on npm as
forgedialog, licensed MIT, and has no runtime dependencies.
The complete bundle is roughly 15 KB gzipped. An application that imports only
forgedialog/alert ships roughly 5.5 KB gzipped, because every entry
point is tree-shakable and carries a size budget that continuous integration enforces
on each pull request.
No. Forge Dialog is framework-agnostic and works with plain JavaScript or a
<script> tag. Optional adapters for React, Vue, Svelte, and Web
Components ship in the same package.
Yes. It renders the native <dialog> element, traps focus while a
dialog is open and restores it to the trigger on close, wires up Escape and backdrop
dismissal, and sets role="dialog" or
role="alertdialog" automatically. Motion honours the
prefers-reduced-motion setting.
The browser built-ins block the main thread, cannot be styled, and offer three fixed shapes. Forge Dialog returns promises instead of blocking, can be styled down to individual components, and covers drawers, sheets, forms, and wizards as well.
Yes. Colour and opacity are set independently for the surface, title, body, and
border; corner radius can be set per corner; shadows are composed from an angle,
distance, blur, spread, and strength; hover effects are opt-in per dialog. All of it
can be changed while a dialog is open by calling update().
Chrome and Edge 88+, Firefox 78+, and Safari 15.4+, plus Node.js 20 or newer for
package tooling and server-side imports. The bundle contains no eval and
no new Function, so it runs under a strict Content Security Policy.
Yes. Forge Dialog is released under the MIT license, which permits commercial use, modification, and redistribution.
Forge Dialog builds on the browser's native <dialog> element,
so focus trapping, the top layer, and inert backgrounds come from the platform rather
than from JavaScript. It has no runtime dependencies, where a Bootstrap modal needs
Bootstrap's CSS and JavaScript. Every entry point is tree-shakable, so an
application that only needs an alert ships about 5.5 KB gzipped rather than the
whole library. It is written in TypeScript and ships types for both ESM and CommonJS.