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.
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
selectform icon), which rotates when open and follows the text color. - Every direct child after the
summarygets the same inline padding. - Consecutive
detailselements get a small gap.
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>@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,
),
);<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, anddialog.returnValuetells you which button was pressed. - The
::backdropuses theoverlaycolor and the optionalbackdrop-filter. - Label the dialog with its heading (
aria-labelledby).
@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.
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');

