Browser support
Check baseline requirements, distinguish automatic fallbacks from application work, and verify components in your target browsers.
On this page
Check browser support for the components your application uses. Master UI relies on modern CSS for its baseline appearance and native elements for behavior. Additional features improve placement, motion or controls; their fallback may be automatic or may require a handler in your application.
Start with the baseline below, then read the enhancement rows for your components. CI exercises the framework scenarios in the Chromium, Firefox and WebKit versions bundled with the pinned Playwright dependency, including the documented fallbacks for invoker commands, interest invokers and anchor positioning. The tables describe feature requirements; they are not a guarantee for every released browser version. Check the feature and the result in each browser you support.
#Baseline requirements
These features are used without a library fallback in the places listed. Layers, nesting and the color functions affect the library broadly; a feature such as subgrid or <dialog> matters where the component uses it.
| Feature | Where it is used |
|---|---|
| Custom properties | Every token, and every property a contract publishes |
Cascade layers (@layer) | Every component and layout rule is in the components layer and the tokens are in theme. It is how a utility wins over a component without !important |
| CSS nesting | Rules are written nested, and the compiled stylesheet keeps the nesting |
light-dark() | Theme colors that change with the color scheme |
oklch() | The values of the color tokens |
color-mix() | Tints, the toned button, glass, the inline chips on an ink surface |
:has() | A parent that reads a child's state: input group, field, segmented control, rating, steps, the empty state of a listbox |
Container size queries (@container) | Card, dialog, data list, navbar, and the form, bento and shell layouts |
subgrid | Calendar, chart, data list |
The individual transform properties (translate, scale) | Lifted control states and overlay entrances |
:focus-visible | Keyboard focus rings on controls |
:dir() | Parts that turn around in right-to-left text, such as a drawer, a breadcrumb separator and a calendar range |
Logical properties and inset | Spacing and placement that follow the direction of the text |
Dynamic viewport units (dvh) | The height limit of a dialog and a command palette. The page and shell layouts write a vh value first |
The popover attribute | Popover, menu, tooltip, the list of a combobox |
<dialog> | Dialog, command palette, toast, a dismissible banner |
Unsupported syntax can invalidate a declaration, selector or whole rule. Losing layers or nesting affects much of the stylesheet; losing a color function can leave the declarations that consume those colors without usable values. An enhancement fallback does not compensate for missing baseline features.
#Enhancements
Each feature below is gated in one of two ways. Most are inside an @supports rule, such as @supports (anchor-scope: --segmented-thumb) or @supports selector(::scroll-marker), written after the rule that draws the fallback. The rest are a single declaration, at-rule or attribute that a browser without the feature ignores, such as interpolate-size, @starting-style or closedby.
The last column describes the fallback or the integration work needed. The platform list in each contract records the component-specific behavior. In particular, a dialog with only commandfor will not open in a browser without invoker commands until you provide the handler described below.
Baseline and enhanced placement
An enhancement changes the result on top of a working baseline. With native popover support, the same surface opens and closes in both cases. CSS anchor positioning places it beside its trigger; without that enhancement, an ordinary popover remains centered in the viewport. The two schematic viewports change only placement. Neither branch supplies a fallback for a browser without popover support.
#Overlays and placement
| Feature | Used by | Without it |
|---|---|---|
Invoker commands: command and commandfor | Dialog, command palette | Call showModal() and close() from a click handler; the stylesheet is the same |
closedby="any" | Dialog, command palette | A click on the scrim does nothing; Escape and the close buttons still close it |
Interest invokers: popover="hint" with interestfor | Tooltip, a popover used as a preview | The tooltip or the preview does not appear; the control keeps its accessible name and still works as a link or a button |
CSS anchor positioning: position-area, position-try-fallbacks | Popover, menu, tooltip, a listbox with the popover attribute | The surface opens and closes the same; it appears centered in the viewport, where the browser places any popover |
anchor-scope and anchor-size() | Combobox | The list sits in the flow directly under the field, at its own width |
anchor-scope with anchor(), for one indicator that moves | Segmented control, tabs, table of contents | Each current option draws its own mark, which changes at once and does not glide |
anchor-scope with anchor(), for a rule that starts at the words | List | The hairline under a row spans the whole row |
@position-try | Context menu | It opens down and to the end of the pointer and does not turn back at the viewport edge |
@starting-style and transition-behavior: allow-discrete | Dialog, popover, menu, tooltip, toast, chart | An overlay appears and leaves at once, without the fade; the bars of a chart appear at full height |
#Fields
| Feature | Used by | Without it |
|---|---|---|
appearance: base-select | Select | The select keeps its well and chevron and opens the platform's own option list; select-option has no effect |
field-sizing: content | An input-auto textarea in input, composer, stepper | The textarea keeps its minimum height and the resize handle; the composer keeps three lines and scrolls; the stepper keeps the width of --stepper-min |
:user-invalid | Input | Native constraints still validate the field, but do not trigger this custom error appearance; aria-invalid="true" still does |
The parts of native fields: ::-webkit-calendar-picker-indicator, ::-webkit-inner-spin-button, ::-webkit-search-cancel-button | Input | The browser keeps its own marks in date, time, number and search fields |
The parts of a native <meter> | Meter | The browser keeps its own meter, which reports the same value and the same three tones in its own style |
#Disclosure
| Feature | Used by | Without it |
|---|---|---|
interpolate-size, with ::details-content on a <details> | Accordion, nav, expand, banner | A panel or a group opens and closes at once; a dismissed banner leaves at once |
::details-content as a preview of closed text | Expand | The text is hidden while closed, as in any <details>, and the toggle still opens it |
The name attribute on <details> | Accordion | Rows open and close independently |
#Scrolling
| Feature | Used by | Without it |
|---|---|---|
Scroll-driven animations: animation-timeline: scroll() | Scroll area, navbar-progress in navbar | The region scrolls the same and its edges stay clean, with no fade; the progress line is not drawn |
Scroll-driven animations: view-timeline and timeline-scope | Slider, range, compare | The track of a slider or a range stays a plain well and the thumbs still show the value; the compare behavior copies the input's value into --compare-position |
Scroll-driven animations: animation-timeline: view() | Wheel | Options are drawn flat, and the one marked aria-selected="true" takes the strong ink |
::scroll-button() and ::scroll-marker | Carousel | No buttons and no dots: the carousel is a row that swipes, scrolls and snaps |
Scroll-state container queries: container-type: scroll-state | Navbar | The pane of the bar is always drawn, at the top of the page too |
scroll-target-group and :target-current | Table of contents | No link is marked until a script or the server sets aria-current on it |
#Layout
| Feature | Used by | Without it |
|---|---|---|
Grid lanes: display: grid-lanes | Masonry | A multi-column box packs the same tiles; they fill down each column instead of across the lanes |
sibling-index() | Sticky stack | Every panel sticks on the same line and covers the one before it whole, so no edges show |
Container query units (cqi) | Breakout | A wide or full child stays in the reading column |
#Drawing
| Feature | Used by | Without it |
|---|---|---|
corner-shape: squircle | Every component, through --corner-shape and --corner-scale | Circular corners at the same apparent size |
corner-shape: bevel | File | The page keeps four round corners and has no folded flap |
Typed attr() | The ring of progress | The ring does not read aria-valuenow: set --progress-ring-value in a style attribute as well |
sibling-index() | Skeleton | Every skeleton in a block starts its band of light at the same moment |
text-wrap: balance and text-wrap: pretty | Heading | The text wraps as usual |
#Checking a feature
Use the exact feature name to find its current compatibility information. For CSS, you can also ask the browser in front of you using the same condition the stylesheet tests:
CSS.supports('(anchor-scope: --mark)')CSS.supports('(appearance: base-select)')CSS.supports('selector(::scroll-marker)')CSS.supports() evaluates CSS support conditions. A positive result is useful for choosing a CSS branch, but it is not a rendering or interaction test. It also does not test HTML attributes such as commandfor.
Verify the component in the target browser after checking the feature:
- Open, close, select or edit it through the path your application provides. Include keyboard use and focus return for overlays.
- Check placement near a viewport edge, narrow layouts and content that scrolls.
- Check the fallback you intend to ship. A missing animation may be acceptable; a missing open handler or an essential instruction hidden in an unavailable tooltip is not.
Keep essential instructions in visible text. A tooltip's omission is only a usable fallback when the underlying control already has its name and purpose.
#Preferences and devices
Support is not only about features. Each stylesheet also answers the queries that describe the reader's device and settings, wherever the component has something to change.
| Query | What changes |
|---|---|
(hover: hover) | Hover states are written inside it, so they apply only where a pointer can hover. A touch does not leave a control looking hovered |
(pointer: coarse) | Targets grow to 44px. A button's minimum height becomes 2.75rem; the label of a checkbox grows around its line without moving what stands near it |
(prefers-reduced-motion: reduce) | Travel is removed: the lift of a control, the scale and slide of an overlay, the glide of an indicator. Fades stay, so a change is still seen |
(forced-colors: active) | The browser removes shadows and replaces colors, so edges and states are drawn again as outlines and fills in system colors such as ButtonText, CanvasText and Highlight |
(prefers-contrast: more) | The theme strengthens its hairline, divider and contour tokens and its muted and disabled inks. Components that read those tokens follow |
(prefers-reduced-transparency: reduce) | The glass of a navbar and a tab bar becomes a solid surface, without the blur |
Theme colors use light-dark() where the schemes differ and follow the color-scheme of the page or subtree; see Default theme.
#The standalone stylesheet
@master/ui/standalone.css is the same source compiled to plain CSS, for a project without Master CSS. Installation shows how to link it.
@import '@master/ui/standalone.css';Compiling resolves the mixins and writes the tokens as custom properties. It does not lower the CSS: the file declares the same layers, keeps the nesting, light-dark() and oklch(), and carries the same @supports rules. Its requirements and its fallbacks are the ones on this page. The same is true of a compiled theme such as @master/ui/dist/themes/paper.css.
The compiled file also declares color-scheme: light dark and supports data-theme="light" and data-theme="dark". Test the actual CSS your application serves if another build tool transforms it after this step.