Share scrolling dialog body styles with modal-body, refs #2790

This commit is contained in:
Simon Willison 2026-09-17 14:42:14 -07:00
commit 269c043da3
7 changed files with 22 additions and 27 deletions

View file

@ -71,6 +71,12 @@ dialog.datasette-modal::backdrop {
border-radius: 20px;
}
:where(.datasette-modal) .modal-body {
min-height: 0;
overflow: auto;
padding: 16px 24px 24px;
}
:where(.datasette-modal) .modal-footer {
padding: 14px 20px;
border-top: 1px solid var(--rule);
@ -1179,7 +1185,6 @@ navigation-search .close-search:focus {
navigation-search .results-container {
box-sizing: content-box;
overflow-y: auto;
height: calc(80vh - 180px);
padding: 0.5rem;
}
@ -1409,7 +1414,7 @@ column-chooser .list-toolbar button:hover {
column-chooser .list-wrap {
flex: 1;
overflow-y: auto;
padding: 0;
overflow-x: hidden;
position: relative;
overscroll-behavior: contain;
@ -1662,8 +1667,7 @@ dialog.mobile-column-actions-dialog {
.mobile-column-actions-dialog .list-wrap {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding: 0;
overflow-x: hidden;
position: relative;
overscroll-behavior: contain;
@ -1817,8 +1821,6 @@ dialog.set-column-type-dialog {
}
.set-column-type-options {
padding: 16px 24px 24px;
overflow-y: auto;
display: grid;
gap: 12px;
}
@ -2018,8 +2020,6 @@ dialog.row-edit-dialog {
.row-edit-fields {
display: grid;
gap: 14px;
padding: 16px 24px 24px;
overflow-y: auto;
}
.row-edit-fields[hidden],
@ -2299,8 +2299,6 @@ textarea.row-edit-input {
.row-edit-bulk {
display: grid;
gap: 8px;
padding: 16px 24px 24px;
overflow-y: auto;
}
.row-edit-bulk-editor {
@ -2616,8 +2614,6 @@ dialog.table-create-dialog {
.table-create-fields {
display: grid;
gap: 18px;
padding: 16px 24px 24px;
overflow-y: auto;
}
.table-create-field {
@ -3081,8 +3077,6 @@ dialog.table-alter-dialog {
.table-alter-fields {
display: grid;
gap: 18px;
padding: 16px 24px 24px;
overflow-y: auto;
}
.table-alter-table-options {
@ -3116,8 +3110,6 @@ dialog.table-alter-dialog {
.table-alter-review {
display: grid;
gap: 12px;
overflow-y: auto;
padding: 16px 24px 24px;
}
.table-alter-review[hidden] {

View file

@ -42,7 +42,7 @@ class ColumnChooser extends HTMLElement {
<button class="select-all">Select all</button>
<button class="deselect-all">Deselect all</button>
</div>
<div class="list-wrap">
<div class="modal-body list-wrap">
<div class="scroll-pulse top"></div>
<div class="scroll-pulse bot"></div>
<ul class="drag-list"></ul>

View file

@ -2159,7 +2159,7 @@ function ensureTableCreateDialog(manager) {
</div>
<form class="table-create-form" method="post" novalidate>
<p class="table-create-error" id="table-create-error" role="alert" tabindex="-1" hidden></p>
<div class="table-create-fields">
<div class="modal-body table-create-fields">
<div class="table-create-field">
<label class="table-create-label" for="table-create-name">Table name</label>
<input class="table-create-input table-create-table-name" id="table-create-name" type="text" name="table" required autocomplete="off">
@ -3909,7 +3909,7 @@ function ensureTableAlterDialog(manager) {
</div>
<form class="table-alter-form" method="post" novalidate>
<p class="table-alter-error" id="table-alter-error" role="alert" tabindex="-1" hidden></p>
<div class="table-alter-fields">
<div class="modal-body table-alter-fields">
<div class="table-alter-columns">
<div class="table-alter-column-headings" aria-hidden="true">
<span>Column</span>
@ -3928,7 +3928,7 @@ function ensureTableAlterDialog(manager) {
</div>
</details>
</div>
<div class="table-alter-review" hidden></div>
<div class="modal-body table-alter-review" hidden></div>
<div class="modal-footer">
<button type="button" class="modal-btn modal-btn-danger table-alter-drop" hidden>Drop table</button>
<button type="button" class="modal-btn modal-btn-ghost table-alter-back" hidden>Back</button>
@ -6984,8 +6984,8 @@ function ensureRowEditDialog(manager) {
<p class="row-edit-summary" id="row-edit-summary" hidden></p>
<p class="row-edit-loading" role="status" aria-live="polite">Loading row...</p>
<p class="row-edit-error" role="alert" tabindex="-1" hidden></p>
<div class="row-edit-fields"></div>
<div class="row-edit-bulk" hidden>
<div class="modal-body row-edit-fields"></div>
<div class="modal-body row-edit-bulk" hidden>
<div class="row-edit-bulk-editor">
<p class="row-edit-bulk-note"><label for="row-edit-bulk-textarea">Paste TSV, CSV, or JSON</label>. You can also <button type="button" class="button-as-link row-edit-bulk-open-file">open a file</button> or drop it onto this textarea</p>
<input class="row-edit-bulk-file-input" type="file" accept=".csv,.tsv,.json,.txt,text/csv,text/tab-separated-values,application/json,text/plain" hidden>

View file

@ -76,7 +76,7 @@ function initMobileColumnActions(manager) {
<span class="modal-title" id="${MOBILE_COLUMN_DIALOG_TITLE_ID}">Column actions</span>
<span class="modal-meta"></span>
</div>
<div class="list-wrap mobile-column-list"></div>
<div class="modal-body list-wrap mobile-column-list"></div>
<div class="modal-footer">
<span class="footer-info">Tap a column to reveal actions.</span>
<button type="button" class="modal-btn modal-btn-ghost mobile-column-actions-done">Done</button>

View file

@ -47,7 +47,7 @@ class NavigationSearch extends HTMLElement {
>
<button type="button" class="close-search" aria-label="Close jump menu">&times;</button>
</div>
<div class="results-container"></div>
<div class="modal-body results-container"></div>
<div class="hint-text">
<span><kbd></kbd> <kbd></kbd> Navigate</span>
<span><kbd>Enter</kbd> Select</span>

View file

@ -198,7 +198,7 @@ function ensureSetColumnTypeDialog() {
</div>
<p class="set-column-type-status"></p>
<p class="set-column-type-error" hidden></p>
<div class="set-column-type-options"></div>
<div class="modal-body set-column-type-options"></div>
<div class="modal-footer">
<span class="footer-info"></span>
<button type="button" class="modal-btn modal-btn-ghost set-column-type-cancel">Cancel</button>

View file

@ -511,7 +511,7 @@ This example adds a button that opens a reusable dialog:
Example dialog
</h2>
</div>
<div style="padding: 1rem; overflow: auto; min-height: 0;">
<div class="modal-body">
This dialog uses Datasette's shared styles and keyboard behavior.
</div>
<div class="modal-footer">
@ -588,6 +588,9 @@ The classes in the example provide built-in styling. None of the classes you add
``modal-meta``
Styles optional metadata, such as a selected-item count, as small monospace text with a rounded background.
``modal-body``
Adds padding and makes overflowing content scroll while the header and footer remain visible. Sets ``min-height: 0``, ``overflow: auto`` and ``padding: 16px 24px 24px``. Add your own layout rules, such as ``display: grid`` and ``gap``, or override the padding for content such as a list.
``modal-footer``
Adds padding, a top border and a background to the action area. Arranges its contents horizontally, with buttons aligned to the right.
@ -613,7 +616,7 @@ You can customize layout and sizing without adding extra classes. For example, t
width: min(720px, calc(100vw - 32px));
}
Long content should have a container with ``overflow: auto`` and ``min-height: 0`` so it can scroll while the header and footer remain visible. Keep these styles scoped to your dialog.
Use ``modal-body`` on the scrolling content container. If that container is inside a form that also contains the footer, the form needs ``display: flex``, ``flex-direction: column``, ``flex: 1 1 auto`` and ``min-height: 0`` so its content can shrink within the dialog.
The dialog shell also uses the CSS custom properties ``--modal-border-radius``, ``--modal-shadow``, ``--modal-backdrop-bg``, ``--modal-backdrop-blur`` and ``--modal-animation-duration``. The shared animations respect the user's reduced-motion preference.