Theming browser-generated UI

Most browser-generated UI can be customized to some extent using CSS. Even if it requires modern features, it degrades gracefully in older browsers, and thus often does not require a polyfill or fallback.

Before re-creating browser UI (form controls, scrollbars, selections, error messages, etc), first verify that:

  1. the browser UI cannot be customized enough for your needs, even with modern CSS,
  2. the desired customization is sufficiently critical to justify the tradeoffs of re-creating built-in UI — most notably losing accessible semantics, keyboard handling, IME, and AT integration that the native UI provides for free.

Example customizations that are possible:

  • Use ::selection to customize highlighted text colors.
  • DON'T apply user-select: none to content text — breaks copy-paste, translation tools, and AT "read from here" gestures. Limit it to chrome (drag handles, toolbars, redundant button labels).
  • Use accent-color to apply the page's accent color to any browser-generated UI.
  • Use color-scheme to have browser UI adapt to light/dark mode.
  • Use scrollbar-color to customize scrollbar colors and scrollbar-width to control scrollbar thickness — keep the thumb visibly distinct from the track (≥3:1), and don't set scrollbar-width: none on scrollable regions (use it only when scrolling is fully replaced by another affordance).
  • Use :user-invalid / :user-valid for validity styling, not :invalid / :valid — they only match after the user has interacted with the field, avoiding the hostile default of flagging required-empty fields as errors on page load. Exclude range sliders when targeting input broadly (e.g., input:not(input[type="range"]):user-valid) so adjusting a slider does not apply field validity borders or backgrounds to it.
  • Buttons and text fields (including <textarea>) can generally be styled as normal elements.
  • Use font-size to scale and other textual properties to control typography

Styling textual fields (<input> & <textarea>)

For most styling purposes (e.g. colors, borders, backgrounds, typography, etc) treat these elements as normal text containers.

  • Use :placeholder-shown and ::placeholder to style input placeholders.
  • Use field-sizing: content to make text fields size to content.
  • For <textarea> elements, use resize: vertical to disable horizontal resizing or resize: none to disable all resizing.

Multiple choice controls (select, radios, checkboxes)

  • To select one among many options presented in a dropdown: Use a <select> + appearance: base-select + ::picker(select). For more info see Branded Select Styling
  • Selecting one or more among multiple options laid out inline in the page: Use a <input type=checkbox> or <input type=radio> inside a <label> for each option. Style via label:has(:checked).
  • Style checkboxes, radios and switches via appearance: none + generated content (::before/::after) or background images to draw the checked state.

Non-textual <input>s (buttons, sliders, file inputs etc.)

  • File inputs: Use ::file-selector-button to style the button.
  • Do not use <input> with a type of button, submit or reset. Use <button> instead and style it as a regular element.
  • Sliders: Use appearance: none + thumb pseudo-elements (::-webkit-slider-thumb, ::-moz-range-thumb, etc) and track pseudo-elements (::-webkit-slider-runnable-track, ::-moz-range-track, etc) for more granular control.