Custom Scrollbar Styling with Tailwind: WebKit Pseudo-Elements and scrollbar-width
AI generated
tw
Tailwind CSS · Scrollbars · Cross-Browser
Custom Scrollbar Styling
Building a subtle, theme-matching scrollbar that works in every browser

The native browser scrollbar often looks out of place in a carefully designed dashboard, gray, thick, and with no connection at all to the surrounding color scheme. With the WebKit-specific ::-webkit-scrollbar pseudo-elements and the standardized scrollbar-width and scrollbar-color properties, its appearance can be tuned precisely without harming the core scrolling function. Getting there, though, means working with two technically completely different APIs that have to be combined cleanly so the result looks equally good in Chrome, Safari, and Firefox.

15 min read ::-webkit-scrollbar scrollbar-width · scrollbar-color

1. Why the native scrollbar often clashes with the design

Browsers render scrollbars by default using the operating system's own appearance, which means the same website visibly shows different scrollbars on Windows, macOS, and Linux. In a dashboard with a clearly defined color scheme, rounded corners, and a consistent design language, that inconsistency stands out especially in long, permanently visible scroll areas, say a sidebar navigation with many entries or a scrollable data table.

Custom scrollbar styling solves this by controlling width, color, and shape of the scrollbar directly through CSS instead of leaving it to the operating system. What matters is that the scrollbar keeps its full functionality despite the visual customization, including drag interaction with the mouse, touch scrolling on mobile devices, and keyboard control, because a purely decorative scrollbar that restricts these interactions would be a clear step backward from the native solution.

2. ::-webkit-scrollbar in detail: Chrome and Safari's pseudo-elements

Chrome, Safari, and every Chromium-based browser support a family of pseudo-elements starting with ::-webkit-scrollbar. ::-webkit-scrollbar itself defines the overall width and height of the scrollbar, ::-webkit-scrollbar-track styles the background track, ::-webkit-scrollbar-thumb the actual, draggable bar, and ::-webkit-scrollbar-thumb:hover allows a dedicated hover state for the thumb, something usually not possible with native scrollbars.

These pseudo-elements are a proprietary, non-standardized WebKit feature that has nonetheless been stable and widely supported for years, because so many browsers share the same rendering engine. The big advantage over the later standard API is the level of detail: corners can be rounded with border-radius, colors can be set as gradients, and even the corner between two intersecting scrollbars can be targeted specifically via ::-webkit-scrollbar-corner, something the leaner standard API simply cannot do.


/* WebKit scrollbar: Chrome, Safari, Edge (Chromium) */
.sidebar::-webkit-scrollbar {
  width: 8px;
}
.sidebar::-webkit-scrollbar-track {
  background: transparent;
}
.sidebar::-webkit-scrollbar-thumb {
  background-color: rgb(100 116 139 / 0.4);
  border-radius: 9999px;
}
.sidebar::-webkit-scrollbar-thumb:hover {
  background-color: rgb(100 116 139 / 0.7);
}

3. scrollbar-width and scrollbar-color: the standardized alternative

Firefox does not support the WebKit pseudo-elements, but instead offers the standardized CSS Scrollbars specification through the properties scrollbar-width and scrollbar-color. scrollbar-width accepts the values auto, thin, or none and only controls width roughly, while scrollbar-color defines two colors in a single value, first the thumb color, then the track color.

This standard API is deliberately more limited than the WebKit pseudo-elements and allows neither rounded corners nor a dedicated hover state for the thumb, but it is now implemented in Chrome and Safari too, so both APIs can sit side by side in the same stylesheet without interfering with each other. Browsers that do not recognize one of the two APIs simply ignore the corresponding rules, producing a robust, mutually complementary fallback behavior.


/* Standard API: Firefox and now Chromium too */
.sidebar {
  scrollbar-width: thin;
  scrollbar-color: rgb(100 116 139 / 0.4) transparent;
}

4. Cross-browser strategy: combining both APIs in the same stylesheet

The most robust solution applies both APIs simultaneously to the same element, so Chrome and Safari use the more detailed WebKit pseudo-elements while Firefox automatically falls back to scrollbar-width and scrollbar-color. Because the two APIs use different selector syntax, they never collide, each browser simply applies the rules it understands and silently ignores the rest.

A common mistake is implementing only the WebKit variant and leaving Firefox users with the unchanged, often noticeably wider default scrollbar, which stands out and looks inconsistent in a direct browser comparison. Conversely, using only scrollbar-width/scrollbar-color without the WebKit pseudo-elements produces a working but far less finely styled result in Chrome and Safari, since corner radii and hover states are missing there.

5. Integrating custom scrollbar styles into a Tailwind project

Since Tailwind itself ships no built-in utility classes for pseudo-elements like ::-webkit-scrollbar, scrollbar styles are in practice cleanest defined as a small, dedicated CSS rule in the global stylesheet file, then activated through a plain class like .custom-scrollbar on the desired container. That class can then be freely combined with other Tailwind utility classes on the same element, no separate plugin required.

For projects that manage theme colors through CSS custom properties, it is worth setting the scrollbar color through such a variable too, instead of hard-coding it. That way the scrollbar adapts automatically whenever the color scheme changes, for instance when switching between several brand themes or toggling between light and dark mode, without ever touching the scrollbar rule itself.

6. Practical example: a subtle scrollbar for a dashboard sidebar

A typical dashboard sidebar with many navigation entries needs a scrollbar that only becomes visible when scrolling is actually possible, while staying slim and restrained in color so it never competes with the actual navigation elements. A width of 6 to 8 pixels, a semi-transparent, muted thumb color, and a transparent track together create exactly that subtle impression, without hiding the scrollbar entirely.

It is also worth adding a slightly more visible hover state for the thumb, so users get clear visual feedback about exactly where they are when deliberately clicking and dragging the scrollbar. That combination of a subdued base color and a more pronounced hover state keeps the sidebar visually calm, without limiting usability for users who want to actively interact with the scrollbar rather than only scroll with the mouse wheel.


/* Sidebar scrollbar: subtle, with clear hover feedback */
.sidebar-scroll {
  scrollbar-width: thin;
  scrollbar-color: rgb(148 163 184 / 0.35) transparent;
}
.sidebar-scroll::-webkit-scrollbar { width: 6px; }
.sidebar-scroll::-webkit-scrollbar-track { background: transparent; }
.sidebar-scroll::-webkit-scrollbar-thumb {
  background-color: rgb(148 163 184 / 0.35);
  border-radius: 9999px;
}
.sidebar-scroll::-webkit-scrollbar-thumb:hover {
  background-color: rgb(148 163 184 / 0.7);
}

7. Adjusting scrollbar colors correctly for dark mode

A scrollbar color that looks subtle in light mode can either become fully invisible or stand out too strongly in dark mode, depending on the contrast against the respective background. It is worth routing the scrollbar color through the same dark mode logic used for the rest of the interface, for example through a dark: variant in Tailwind or a CSS custom property that takes a different value in the dark mode context.

A frequently overlooked point is that both scrollbar-color and the WebKit pseudo-elements need to be adjusted separately for dark mode, because neither API reacts automatically to color scheme changes. Anyone who only updates one of the two variants for dark mode ends up with a wrong-looking scrollbar in either Firefox or Chromium-based browsers, even though the rest of the interface switches correctly between modes.

8. Accessibility: contrast and minimum size for customized scrollbars

A custom scrollbar that is too thin or too low in contrast significantly hinders users with limited fine motor control or reduced vision from clicking and dragging it precisely, simply because the hit target becomes too small. As a rule of thumb, the visible scrollbar thumb should never be narrower than around 6 pixels, and the color contrast between thumb and background should remain clearly perceivable even in its base state, not only on hover.

It also matters that a visually toned-down scrollbar is never effectively disabled with pointer-events: none or similar properties just to make it appear more subtle. The scrollbar must remain clickable and draggable by mouse at all times, even if its base color was deliberately chosen to be muted, otherwise an important interaction path for scrolling, one some users specifically prefer, is lost entirely.

9. Common pitfalls with custom scrollbar styling

On macOS, many users hide scrollbars entirely by default and only briefly reveal them during active scrolling, an operating system setting that CSS cannot and should not override. In that case custom scrollbar styles only affect the briefly revealed scrollbar, something that is easily missed when testing exclusively on a Windows machine and leads to wrong assumptions about visibility.

Another common mistake is forgetting scrollbar width in layout calculations, especially with very narrow, overlapping scrollbars combined with content that sits flush against the container edge. A small right padding on the scrolling container prevents text or interactive elements from ending up directly under the scrollbar and becoming harder to click there, particularly on touch-based devices with thicker overlay scrollbars.

API Supported browsers Controllable aspects Limitation
::-webkit-scrollbar Chrome, Safari, Edge (Chromium) Width, color, radius, hover state, corner Not standardized, no Firefox
scrollbar-width Firefox, now Chromium too Only auto/thin/none No fine-grained pixel width
scrollbar-color Firefox, now Chromium too Thumb and track color No radius, no dedicated hover
Combining both APIs All current browsers Best possible rendering per engine Requires duplicated rules in the stylesheet

Mironsoft

Tailwind CSS architecture, design systems, and performance

Tailwind frontends that stay maintainable despite thousands of utility classes?

We review existing Tailwind projects for bloated class lists, inconsistent design tokens, and unused CSS remnants, then build a design system that scales cleanly instead of getting messier with every component.

Design System Review

Checking tokens, spacing scale, and component consistency for maintainability.

Performance Optimization

Systematically reducing CSS bundle size, purge configuration, and load times.

Component Architecture

Building reusable, well-structured components instead of sprawling class lists.

10. Summary

Custom Scrollbar Styling: The Essentials at a Glance

Two APIs needed

::-webkit-scrollbar for Chrome/Safari, scrollbar-width/scrollbar-color for Firefox, combined in the same stylesheet.

Tailwind integration

Define as a dedicated CSS class in the global stylesheet file, then combine freely with Tailwind utilities.

Dark mode

Both APIs need separate adjustment for the dark mode context, neither reacts automatically to color scheme switches.

Accessibility

At least 6 pixels of thumb width, clear contrast, scrollbar remains clickable and draggable at all times.

11. FAQ: Custom Scrollbar Styling: The Essentials at a Glance

1Why do I need two different CSS APIs for a custom scrollbar?
::-webkit-scrollbar is a proprietary Chromium/Safari feature, Firefox instead supports the standardized properties scrollbar-width and scrollbar-color. Both need to be combined for full browser coverage.
2Do ::-webkit-scrollbar and scrollbar-width collide if I set both?
No, each browser only applies the rules it recognizes and silently ignores the rest. Both APIs can safely sit side by side in the same stylesheet.
3Can I set an exact pixel width with scrollbar-width?
No, scrollbar-width only accepts auto, thin, or none. Exact pixel values and corner radii are only possible through the WebKit pseudo-element API.
4Are there Tailwind utility classes for scrollbar styling?
Tailwind itself ships no built-in utilities for ::-webkit-scrollbar. The usual approach is a small, dedicated CSS class in the global stylesheet file, then combined with other utilities.
5Do I need to adjust scrollbar colors separately for dark mode?
Yes. Neither scrollbar-color nor the WebKit pseudo-elements react automatically to color scheme switches, both need to be driven by the same dark mode logic as the rest of the interface.
6Why do I sometimes not see my custom scrollbar on macOS at all?
macOS hides scrollbars by default and only briefly shows them during scrolling. That is an operating system setting that CSS should not try to override.
7How narrow can an accessible scrollbar be at most?
As a rule of thumb, the visible thumb should never be narrower than around 6 pixels, so users with limited fine motor control can still reliably hit it.
8Should I make the scrollbar more subtle with pointer-events: none?
No. The scrollbar must remain clickable and draggable even if its color is deliberately muted, otherwise an important interaction path is lost for some users.
9Why should the scrolling container get a small right padding?
So text or interactive elements do not end up directly under the scrollbar and become harder to click there, especially with thicker overlay scrollbars on touch devices.
10Does ::-webkit-scrollbar work on a single scrollable div, not just the whole page?
Yes, the pseudo-elements apply to any element with overflow: auto or overflow: scroll, not only the page's root element.