Details and Dialog

Spruce CSS styles the native disclosure (details) and modal (dialog) elements. They are accessible and keyboard friendly out of the box, so you need little or no JavaScript.

The selectors use :where(), so their specificity is zero: any of your own styles win. Turn them off with the details and dialog generators.

Details

What is Spruce CSS?

A Sass-based, minimalistic CSS framework to get the foundation right for any web-based project.

Is it open by default?

Use the open attribute to render it expanded.

<details>
    <summary>What is Spruce CSS?</summary>
    <p>A Sass-based, minimalistic CSS framework…</p>
</details>
  • The marker is replaced with a chevron (a mask of the select form icon), which rotates when open and follows the text color.
  • Every direct child after the summary gets the same inline padding.
  • Consecutive details elements get a small gap.

Exclusive Accordion

Give the elements the same name attribute, and only one of them can be open at a time (supported in every modern browser):

First question

Opening another one closes this.

Second question

No JavaScript involved.

<details name="faq">…</details>
<details name="faq">…</details>

Variables

@use 'sprucecss/scss/spruce' with (
  $details: (
    'border-radius': map.get($display, 'border-radius-sm'),
    'border-width': 1px,
    'gap': map.get($spacers, 'xs'),
    'icon-size': 1em,
    'padding': map.get($spacers, 's'),
    'summary-font-weight': 600,
  ),
);

Dialog

Delete project?

This action can’t be undone.

<button class="btn btn--primary" type="button" data-open="confirm-dialog">Open dialog</button>

<dialog id="confirm-dialog" aria-labelledby="confirm-dialog-title">
    <h2 id="confirm-dialog-title">Delete project?</h2>
    <p>This action can’t be undone.</p>
    <form method="dialog">
        <button class="btn btn--danger" value="delete">Delete</button>
        <button class="btn btn--ghost-secondary" value="cancel">Cancel</button>
    </form>
</dialog>
document.querySelector('[data-open="confirm-dialog"]').addEventListener('click', () => {
  document.getElementById('confirm-dialog').showModal();
});
  • Open it with showModal(): the browser traps the focus, closes it with Esc, makes the page inert and returns the focus to the opener.
  • A form method="dialog" closes the dialog on submit, and dialog.returnValue tells you which button was pressed.
  • The ::backdrop uses the overlay color and the optional backdrop-filter.
  • Label the dialog with its heading (aria-labelledby).

Variables

@use 'sprucecss/scss/spruce' with (
  $dialog: (
    'backdrop-filter': none, // like blur(4px)
    'border-radius': map.get($display, 'border-radius-lg'),
    'border-width': 1px,
    'inline-size': 40rem,
    'padding': map.get($spacers, 'm'),
  ),
);

Need a side panel instead? See the Drawer component, built on the same element.

Generators

Both are generated by generate-styles. To use them with a custom selector (for example, only with a class), turn off the generator and include the mixin yourself:

@use 'sprucecss/scss/spruce' as *;

@include generate-details('.accordion');
@include generate-dialog('.modal');

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.