Dialog with details & summary

Combining Dialog with the native details element in React so users can interact with it before JavaScript finishes loading.

Open preview in a new tab
Show modal
Edit withViteNext.js
import "./style.css";
import { useEffect, useRef, useState } from "react";
import * as Ariakit from "@ariakit/react";
function useLoaded() {
const [loaded, setLoaded] = useState(false);
useEffect(() => setLoaded(true), []);
return loaded;
export default function Example() {
const ref = useRef<HTMLDetailsElement>(null);
const loaded = useLoaded();
const [open, setOpen] = useState(false);
// Hydrate the dialog state. This is necessary because the user may have
// opened the dialog before JavaScript has loaded.
useEffect(() => setOpen(!!ref.current?.open), []);
return (
onToggle={(event) => setOpen(}
<Ariakit.Button className="button" render={<summary />}>
Show modal
onClose={() => setOpen(false)}
// We're setting the modal prop to true only when JavaScript is enabled.
// This means that the dialog will initially have a non-modal state with
// no backdrop element, allowing users to interact with the content
// behind. This is necessary because, before JavaScript finishes
// loading, we can't automatically move focus to the dialog.
backdrop={loaded && <div className="backdrop" />}
<Ariakit.DialogHeading className="heading">
<p className="description">
Your payment has been successfully processed. We have emailed your
<Ariakit.DialogDismiss className="button">OK</Ariakit.DialogDismiss>



Resetting the default styles

By default, browsers apply some default styles to the details element. We can reset them with the following CSS:

.button {
appearance: none;
.button::-webkit-details-marker {
display: none;

You can learn more about styling Ariakit components on the Styling guide.

Follow updates

Join 1,000+ subscribers and receive monthly updates with the latest improvements on Examples.

Read latest issue

No Spam. Unsubscribe at any time.