# modest-ui > A minimal, themeable CSS component library. IMPORTANT: The npm package is "mdst-ui", NOT "modest-ui". The name "modest-ui" on npm is an UNRELATED Vue library — do not install it. This package is named "mdst-ui" to match its class/token prefix (.mdst-ui, --mdst-*). Whenever a human says "modest-ui", the package to install is "mdst-ui". - Version: 2.0.0 (this file describes v2; class names differ from v1) - Package (npm): mdst-ui - Docs: https://modest-ui.com - GitHub: https://github.com/thisismodest/modest-ui - License: MIT ## Installation CDN (pin the major version so markup and CSS match): npm: npm install mdst-ui # NOT "npm install modest-ui" Import (bundled): @import "mdst-ui/dist/modest-ui.css"; Cherry-pick (tokens first): @import "mdst-ui/base/tokens.css"; @import "mdst-ui/components/button/button.css"; modest-ui is CSS only. JavaScript shown in the docs is example code for behaviour you own (switching tabs, showing a toast, revealing a password). ## Rules for writing modest-ui markup 1. Put `class="mdst-ui"` on `` (or a wrapper) and write semantic HTML. Bare elements inside it are styled with no classes. 2. Add a modifier class only for a variant: ` 7 ``` --- ### Banner `.mdst-banner` Full-width message strip for cookie consent, alerts, and announcements. Sits in the page flow, sticks to the top or bottom of a section, or fixes to the viewport. Status variants are modifier classes; visibility is driven by data-state. Classes: - `.mdst-banner` - `.mdst-banner__actions` - `.mdst-banner__close` - `.mdst-banner__content` - `.mdst-banner--border-bottom` - `.mdst-banner--border-end` - `.mdst-banner--border-start` - `.mdst-banner--border-top` - `.mdst-banner--borderless` - `.mdst-banner--bottom` - `.mdst-banner--danger` - `.mdst-banner--end` - `.mdst-banner--fixed` - `.mdst-banner--info` - `.mdst-banner--sm` - `.mdst-banner--start` - `.mdst-banner--success` - `.mdst-banner--top` - `.mdst-banner--warning` ```html
Scheduled maintenance on Sunday.
...
...
We use analytics cookies.
...
...
``` --- ### Breadcrumbs `.mdst-breadcrumbs` Navigation breadcrumb trail with separator support. Works classless via aria-label or with explicit class. Classes: - `.mdst-breadcrumbs` - `.mdst-breadcrumbs--arrow` - `.mdst-breadcrumbs--sm` ```html ``` --- ### Button `.mdst-button` Button with solid, borderless, and danger variants, toggle and disabled states, and three sizes. Variants are just variables, so you can make your own. Classes: - `.mdst-button` - `.mdst-button--borderless` - `.mdst-button--danger` - `.mdst-button--lg` - `.mdst-button--sm` - `.mdst-button--solid` ```html Unavailable /* Hover: any box-shadow, or none */ :root { --mdst-button-hover-shadow: none; } /* Prefer an underline? Add your own rule */ .mdst-ui button:hover { text-decoration: underline; } .btn-brand { --mdst-button-tone: #4338ca; } ``` --- ### Card `.mdst-card` A bordered container for grouping content with optional header, body, and footer sections. Classes: - `.mdst-card` - `.mdst-card__body` - `.mdst-card__footer` - `.mdst-card__header` - `.mdst-card--borderless` - `.mdst-card--flush` - `.mdst-card--interactive` - `.mdst-card--sm` - `.mdst-card__footer--borderless` - `.mdst-card__header--borderless` ```html
Content
Title
Content goes here.
Clickable card
Tight content
Table card
...
Title
Content
Content
``` --- ### Checkbox `.mdst-input` Checkbox, and a toggle switch for checkboxes with role="switch". Label support, checked, and disabled states. Classes: - `.mdst-input` - `.mdst-input--pill` ```html ``` --- ### Code `.mdst-code` Inline code component for displaying code snippets within text. Classes: - `.mdst-code` ```html

Use const x = 1 to declare a variable.

``` --- ### Color `.mdst-input` Native colour input drawn as a round or square swatch. Classes: - `.mdst-input` - `.mdst-input--square` ```html
``` --- ### Date & time `.mdst-input` Date, time, datetime-local, month, and week inputs, styled to match the text fields. The pickers are the browser's own. Classes: - `.mdst-input` ```html ``` --- ### Details `.mdst-details` Expandable details/accordion component with section variants. Classes: - `.mdst-details` - `.mdst-details--borderless` - `.mdst-details--section` - `.mdst-details--sm` ```html
Click to expand

Content goes here.

Already open

Content goes here.

Section Title

Content goes here.

Question 1

Answer 1

Question 2

Answer 2

Question 3

Answer 3

``` --- ### Dialog `.mdst-dialog` Modal dialog component with header, body, footer structure and multiple sizes. Classes: - `.mdst-dialog` - `.mdst-dialog__body` - `.mdst-dialog__close` - `.mdst-dialog__footer` - `.mdst-dialog__header` - `.mdst-dialog__title` - `.mdst-dialog--full` - `.mdst-dialog--lg` - `.mdst-dialog--sm` ```html

Dialog Title

Dialog content goes here.

``` --- ### Drawer `.mdst-drawer` Side panel built on native . Backdrop, focus trapping, Escape to close, and accessibility for free. Classes: - `.mdst-drawer` - `.mdst-drawer__body` - `.mdst-drawer__close` - `.mdst-drawer__footer` - `.mdst-drawer__header` - `.mdst-drawer--full` - `.mdst-drawer--lg` - `.mdst-drawer--sm` - `.mdst-drawer--start` ```html
Drawer Title

Content goes here.

... ... ... ... ``` --- ### Dropdown `.mdst-dropdown` Native select dropdown with borderless and inline variants in multiple sizes. Classes: - `.mdst-dropdown` - `.mdst-dropdown--borderless` - `.mdst-dropdown--inline` - `.mdst-dropdown--lg` - `.mdst-dropdown--sm` ```html

Sort by

``` --- ### File `.mdst-input` Native file input with a styled "Choose file" button. No JavaScript required. Classes: - `.mdst-input` - `.mdst-input--borderless` - `.mdst-input--solid` ```html ``` --- ### Form `.mdst-form` A light structure layer for plain forms: fields stack under their labels, fieldsets get a border and legend, and invalid fields show in the error colour. Zero specificity, so your own styles always win. Classes: - `.mdst-fieldset` - `.mdst-form` - `.mdst-legend` ```html
Account
…
…
/* Tighter or looser forms */ form { --mdst-flow-space: 0.75rem; } ``` --- ### Text `.mdst-input` Text, email, number, search, tel, and url inputs, plus textarea. Styled classless or with .mdst-input, with borderless, focus, and invalid states. Classes: - `.mdst-input` - `.mdst-input--borderless` ```html ``` --- ### Meter `.mdst-meter` Styles the native element for scalar values like storage, scores, or password strength. Fill colour follows the low, high, and optimum attributes. Classes: - `.mdst-meter` - `.mdst-meter--lg` - `.mdst-meter--sm` ```html 60% 92 of 256 GB Fair 212 GB 50% 50%
75%
``` --- ### OTP `.mdst-otp-input` One-time password digits with danger and success states. Auto-advance and paste are a few lines of your own JavaScript; the docs include an example. Classes: - `.mdst-otp-input` - `.mdst-otp-input__separator` - `.mdst-otp-input--danger` - `.mdst-otp-input--success` ```html
...
...
``` --- ### Password `.mdst-password-input` Password field with an eye toggle. The field is a real type="password"; showing the text takes a few lines of your own JavaScript. Classes: - `.mdst-password-input` ```html
``` --- ### Popover `.mdst-popover` Popover component using the native Popover API for tooltips and dropdowns. Classes: - `.mdst-popover` - `.mdst-popover--anchored` - `.mdst-popover--lg` - `.mdst-popover--sm` ```html

Popover content

Anchored below the button

Won't close on outside click

``` --- ### Pre `.mdst-pre` Preformatted code block component for displaying multi-line code. Classes: - `.mdst-pre` - `.mdst-pre--borderless` - `.mdst-pre--scroll` - `.mdst-pre--sm` ```html
{
  "json": "content"
}
single line
no border
long content...
``` --- ### Progress `.mdst-progress` Progress bar component styling the native element with size and status variants. Classes: - `.mdst-progress` - `.mdst-progress--danger` - `.mdst-progress--lg` - `.mdst-progress--sm` - `.mdst-progress--success` ```html 60% Loading… 100% 35% 50% 50%
75%
``` --- ### Radio `.mdst-input` Radio button with label support, group layout, and selectable cards. Classes: - `.mdst-input` - `.mdst-radio-card` - `.mdst-radio-card-group` - `.mdst-radio-group` - `.mdst-radio-group--horizontal` ```html
...
``` --- ### Range `.mdst-input` Range slider styled to match the rest of the library. Classes: - `.mdst-input` ```html ``` --- ### Skeleton `.mdst-skeleton` Placeholder loading shapes with an animated shimmer effect. Supports text, heading, and circle variants for building loading states. Classes: - `.mdst-skeleton` - `.mdst-skeleton--circle` - `.mdst-skeleton--heading` - `.mdst-skeleton--text` ```html
``` --- ### Spinner `.mdst-spinner` Animated loading spinner using CSS borders and rotation. Inherits color from context with size variants. Classes: - `.mdst-spinner` - `.mdst-spinner--lg` - `.mdst-spinner--sm` ```html
Something went wrong
``` --- ### Stepper `.mdst-stepper` Multi-step progress indicator driven by data-state attributes for completed, active, upcoming, and error states. Classes: - `.mdst-stepper` - `.mdst-stepper__indicator` - `.mdst-stepper__label` - `.mdst-stepper__step` - `.mdst-stepper--sm` - `.mdst-stepper--vertical` ```html data-state="completed" → Step is done (filled indicator, solid connector) data-state="active" → Current step (bold indicator and label) data-state="upcoming" → Not yet reached (muted indicator and label) data-state="error" → Step has an error (error-colored indicator and label) step.dataset.state = "completed"; step.dataset.state = "active"; step.dataset.state = "error"; ``` --- ### Table `.mdst-table` Table component with bordered, striped, small, equal, and stacked variants. Classes: - `.mdst-table` - `.mdst-table-wrap` - `.mdst-table--bordered` - `.mdst-table--fixed` - `.mdst-table--sm` - `.mdst-table--stack` - `.mdst-table--striped` ```html
Header Header
Cell Cell
...
...
...
``` --- ### Tabs `.mdst-tabs` Data-attribute-driven tabbed interface with pills, vertical, and small variants. Classes: - `.mdst-tabs` - `.mdst-tabs__list` - `.mdst-tabs__panel` - `.mdst-tabs__tab` - `.mdst-tabs--pills` - `.mdst-tabs--sm` - `.mdst-tabs--vertical` ```html data-state="active" Tab is selected data-state="inactive" Tab is not selected data-disabled Tab cannot be selected (boolean attribute) data-disabled="true" Same as above (explicit value) data-state="active" Panel is visible data-state="inactive" Panel is hidden (display: none) ``` --- ### Tag `.mdst-tag` Inline labels for status, categories, and metadata. Supports solid, subtle, and borderless variants, status colours, with optional dismiss button. Classes: - `.mdst-tag` - `.mdst-tag__dismiss` - `.mdst-tag--borderless` - `.mdst-tag--danger` - `.mdst-tag--info` - `.mdst-tag--interactive` - `.mdst-tag--lg` - `.mdst-tag--muted` - `.mdst-tag--pill` - `.mdst-tag--sm` - `.mdst-tag--solid` - `.mdst-tag--subtle` - `.mdst-tag--success` - `.mdst-tag--warning` ```html Tag Solid Subtle Ghost Pill Active Failed Archived Online Offline Small Large Label ``` --- ### Toast `.mdst-toast` Notification toast messages with success, info, warning, and danger variants. Visibility is driven by data-state. Classes: - `.mdst-toast` - `.mdst-toast-group` - `.mdst-toast__close` - `.mdst-toast--danger` - `.mdst-toast--info` - `.mdst-toast--success` - `.mdst-toast--warning` ```html
Your changes have been saved. Something went wrong.
``` --- ### Toolbar `.mdst-toolbar` A wrapping row of controls with groups, attached (segmented) groups, separators, and a spacer to push actions to the end. Toggle buttons use aria-pressed. Classes: - `.mdst-toolbar` - `.mdst-toolbar__group` - `.mdst-toolbar__separator` - `.mdst-toolbar__spacer` - `.mdst-toolbar--bordered` - `.mdst-toolbar__group--attached` ```html
``` --- ### Tooltip `.mdst-tooltip` Tooltip component using the native Popover API and CSS anchor positioning. Classes: - `.mdst-tooltip` - `.mdst-tooltip--end` - `.mdst-tooltip--start` - `.mdst-tooltip--top` ```html
Helpful tooltip text
Above the trigger
Left of the trigger
Right of the trigger
``` --- ### Typography `.mdst-*` Typography utilities for headings, body text, small text, and font styles. Classes: - `.mdst-a` - `.mdst-abbr` - `.mdst-blockquote` - `.mdst-cite` - `.mdst-del` - `.mdst-em` - `.mdst-fieldset` - `.mdst-h1` - `.mdst-h2` - `.mdst-h3` - `.mdst-h4` - `.mdst-h5` - `.mdst-h6` - `.mdst-hr` - `.mdst-ins` - `.mdst-kbd` - `.mdst-li` - `.mdst-mark` - `.mdst-ol` - `.mdst-p` - `.mdst-s` - `.mdst-samp` - `.mdst-small` - `.mdst-strong` - `.mdst-sub` - `.mdst-sup` - `.mdst-ul` - `.mdst-var` - `.mdst-hr--flush` - `.mdst-p--lg` - `.mdst-p--muted` - `.mdst-p--sm` - `.mdst-ul--unstyled` ```html

Heading 1

Heading 2

Default paragraph.

Muted text.

Link Bold Italic Highlight Ctrl + K CSS Removed Added £40 £32 The Elements of Style File saved. w H2O mc2
Quote


  • Item
``` --- ### Utilities `.mdst-*` Small utility classes for common layout and text patterns: screen-reader-only, truncation, centering, and more. Classes: - `.mdst-mono` - `.mdst-muted` - `.mdst-sr-only` - `.mdst-truncate` ```html Skip to content
Long text that will be truncated...
Secondary text monospace ``` --- ## Theming Example ```css :root { --mdst-color-fg: #1a1a1a; --mdst-color-bg: #ffffff; --mdst-color-border: #e5e5e5; --mdst-color-focus: #2563eb; --mdst-radius: 6px; --mdst-font-text: Charter, Georgia, serif; } ``` Setting colour tokens yourself replaces both the light and dark values. To keep dark mode, set them inside `@media (prefers-color-scheme: dark)` too, or use `light-dark()`: ```css :root { color-scheme: light dark; --mdst-color-fg: light-dark(#1a1a1a, #f5f5f5); --mdst-color-bg: light-dark(#ffffff, #111111); } ``` --- ## Quick Class Reference Avatar: .mdst-avatar .mdst-avatar-group | --lg --sm --square --xl Badge: .mdst-badge | --danger --dot --info --lg --muted --sm --solid --subtle --success --top-end --warning Banner: .mdst-banner + __actions __close __content | --border-bottom --border-end --border-start --border-top --borderless --bottom --danger --end --fixed --info --sm --start --success --top --warning Breadcrumbs: .mdst-breadcrumbs | --arrow --sm Button: .mdst-button | --borderless --danger --lg --sm --solid Card: .mdst-card + __body __footer __header | --borderless --flush --interactive --sm --borderless --borderless Checkbox: .mdst-input | --pill Code: .mdst-code Color: .mdst-input | --square Date & time: .mdst-input Details: .mdst-details | --borderless --section --sm Dialog: .mdst-dialog + __body __close __footer __header __title | --full --lg --sm Drawer: .mdst-drawer + __body __close __footer __header | --full --lg --sm --start Dropdown: .mdst-dropdown | --borderless --inline --lg --sm File: .mdst-input | --borderless --solid Form: .mdst-fieldset .mdst-form .mdst-legend Text: .mdst-input | --borderless Meter: .mdst-meter | --lg --sm OTP: .mdst-otp-input + __separator | --danger --success Password: .mdst-password-input Popover: .mdst-popover | --anchored --lg --sm Pre: .mdst-pre | --borderless --scroll --sm Progress: .mdst-progress | --danger --lg --sm --success Radio: .mdst-input .mdst-radio-card .mdst-radio-card-group .mdst-radio-group | --horizontal Range: .mdst-input Skeleton: .mdst-skeleton | --circle --heading --text Spinner: .mdst-spinner | --lg --sm Stepper: .mdst-stepper + __indicator __label __step | --sm --vertical Table: .mdst-table .mdst-table-wrap | --bordered --fixed --sm --stack --striped Tabs: .mdst-tabs + __list __panel __tab | --pills --sm --vertical Tag: .mdst-tag + __dismiss | --borderless --danger --info --interactive --lg --muted --pill --sm --solid --subtle --success --warning Toast: .mdst-toast .mdst-toast-group + __close | --danger --info --success --warning Toolbar: .mdst-toolbar + __group __separator __spacer | --bordered --attached Tooltip: .mdst-tooltip | --end --start --top Typography: .mdst-a .mdst-abbr .mdst-blockquote .mdst-cite .mdst-del .mdst-em .mdst-fieldset .mdst-h1 .mdst-h2 .mdst-h3 .mdst-h4 .mdst-h5 .mdst-h6 .mdst-hr .mdst-ins .mdst-kbd .mdst-li .mdst-mark .mdst-ol .mdst-p .mdst-s .mdst-samp .mdst-small .mdst-strong .mdst-sub .mdst-sup .mdst-ul .mdst-var | --flush --lg --muted --sm --unstyled Utilities: .mdst-mono .mdst-muted .mdst-sr-only .mdst-truncate