Skip to content

Dark Docs by winghongchan

Dark Docs screenshot



LicenseGNU General Public License v3





Learn how we calculate statistics in the FAQ.

Total views

Total installs

Weekly installs

Weekly updates


A dark theme for Google Docs web, based on the colors used in its Material You styled mobile apps.


Latest updates

  • 2023.06.01

    • The Menu and Search icons on the home screen are legible again.
    • The new command search button (not made available by Google to all users) has been darkened.
  • 2023.05.19

    • The emoji picker has been repaired (apparently they decided to rewrite the whole thing).
    • The interfaces to react to comments with emojis and view reaction details have been darkened.
    • The text fields to add or reply to comments more closely resemble the original design.
    • Suggested replies to comments have been darkened.
    • The Chat sidebar header bar brightens more when you scroll through the chat history, to match other sidebars.
    • The text field to add a chat message now has hover and focus outlines.
    • The homepage header is repaired yet again, and is more resilient to Google changing class names.
    • The template gallery has been repaired and the settings dialog has been darkened.
  • 2023.05.06

    • The list of comments (that appears when you press the comment history button beside the Share button) no longer flashes brightly when you open it for the first time after loading Google Docs.
    • The Docs label on the homepage is legible, yet again.
    • I am now working on Google Slides support!

Browser-specific notes

Firefox (and LibreWolf, &c.) users

Dark Docs uses the newer :has() selector. Support for it in Firefox is currently in development, but you can enable support for it by setting the layout.css.has-selector.enabled preference to true. Follow along with Mozilla’s work on this at Bugzilla.

Chromium-based browsers have full support of the :has() selector.

If you are using an older version of Firefox (prior to version 113), you may not see some hover and focus effects because they rely on the color-mix() function to reduce the size of Dark Docs. To enable support for it, go to about:config and set layout.css.color-mix.enabled to true. Firefox 113 and newer has this enabled by default.

Chrome (and Edge, Vivaldi, &c.) users

By default, Dark Docs uses the Invert document filter so your document appears with an inverted colour scheme (approximately white on black). Since Google Docs renders each page as a single element, there doesn’t seem to be a way to un-invert images so that they look normal. If you must view images un-inverted, you may change the document filter to “Dim” or “None” in the configuration dialog.


Source code

Source code has over 10K characters, so we truncated it. You can inspect the full source code on install link.
/* ==UserStyle==
@name           Dark Docs
@version        2023.06.01
@description    A new version of Dark Docs, made for Google Docs’ Material U redesign. 
@author         Walter winghongchan
@license        GPL-3.0-or-later
@preprocessor   less
@var            select document-filter "Document filter" {"none:None": "none", "dim:Dim": "contrast(80%) brightness(90%)", "invert:Invert*": "var(--darkfilter)"}
@var            number document-contrast "Document contrast while inverted" [76, 40, 100, 1, "%"]
@var            checkbox respect-pageless-document-color "Respect page color of pageless documents while a document filter is applied. May be laggy." 0
@var            checkbox has-selector-missing-warning "Warn me if the :has() selector is not available in my browser." 1
==/UserStyle== */

/* Dark Docs is licensed under the GNU GPL v3

Dark Docs: a Material You dark mode for Google Docs. 
Copyright (C) 2023 Walter <winghongchan> 

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

Read a copy of this license at 

/* Notice for Firefox (or LibreWolf, &c.) users
Dark Docs next uses the :has() selector, which is experimental on Firefox at the moment. To enable it, go to about:config and set layout.css.has-selector.enabled to true. Chromium‐based browsers have full support. 
Follow along with Mozilla’s development on the :has selector at 

If you are using an older version of Firefox (prior to version 113), you may not see some hover and focus effects because they rely on the color-mix() function to reduce the size of Dark Docs. To enable support for it, go to about:config and set layout.css.color-mix.enabled to true. Firefox 113 and newer has this enabled by default. 

/* Notice for Chrome (or Vivaldi, Edge, &c.) users
Google Docs renders each page as a single <canvas> element, which may have made it impossible to un-invert images while using the Invert document filter in Dark Docs. If you need to view images un-inverted, open the Stylus extension, click on the cog beside “Dark Docs”, and change the Document filter to “Dim” or “None”.
@-moz-document url-prefix(""), url-prefix(""), regexp("https:\\/\\/docs\\.google\\.com\\/sharing\\/boq\\/driveshare\\?[\\s\\S]+origin=https%3A%2F%2Fdocs\\.google\\.com"), url-prefix(""), url-prefix(""), regexp("https:\\/\\/docs\\.google\\.com\\/picker\\/v2\\/home\\?req=.*%22Google%20Drive%22.*%22Replace%22.*%22replace-image%22.*&parent=https%3A%2F%2Fdocs\\.google\\.com&pfname=&rpctoken=[0-9]+"), regexp("(https:\\/\\/\\/_\\/frame\\?authUser=\\d+&frameType=2&"), regexp("https:\\/\\/docs\\.google\\.com\\/picker\\/v2\\/home\\?req=.*%22explore-drive.*&parent=https%3A%2F%2Fdocs\\.google\\.com&pfname=&rpctoken=[0-9]+"), regexp("https:\\/\\/docs\\.google\\.com\\/picker\\/v2\\/home\\?req=.*%22Google%20Photos%22.*&parent=https%3A%2F%2Fdocs\\.google\\.com&pfname=&rpctoken=[0-9]+") {
// Variables
  :root {
    // Colour
    --ddocs-primary: #a8c7fa;
    --ddocs-primary-icon: invert(100%) hue-rotate(180deg) brightness(75%) saturate(400%);
    --ddocs-primary-hover: rgba(168, 199, 250, var(--ddocs-hover-state-layer-opacity)); // That’s right, standard (no fill or outline) icon buttons, when enabled (selected) and hovered, use a state layer of colour primary! Not on-primary-container or something.
    --ddocs-primary-focus: rgba(168, 199, 250, var(--ddocs-focus-state-layer-opacity));
    --ddocs-primary-pressed: rgba(168, 199, 250, var(--ddocs-pressed-state-layer-opacity));
    --ddocs-on-primary: #062e6f;
    --ddocs-on-primary-hover: #9bbaef;
    --ddocs-on-primary-focus: #94b4e9;
    --ddocs-on-primary-pressed: #94b4e9;
    --ddocs-primary-container: #004a77;
    --ddocs-on-primary-container: #c2e7ff;
    --ddocs-on-primary-container-icon: invert(100%) hue-rotate(180deg) saturate(150%);
    --ddocs-on-primary-container-hover: #0f5682;
    --ddocs-on-primary-container-focus: #185d88;
    --ddocs-on-primary-container-pressed: #185d88;
    --ddocs-secondary: #7fcfff;
    --ddocs-on-secondary: #003355;
    --ddocs-secondary-container: #0842a0;
    --ddocs-secondary-container-hover: #184fa8; // Determined the colour by overlapping the -on colour at 8% opacity on top of the container. Not a problem until Dark Docs begins support for custom colours. 
    --ddocs-secondary-container-focus: #2156ac;
    --ddocs-on-secondary-container: #d3e3fd;
    --ddocs-on-secondary-container-hover: rgba(211, 227, 253, var(--ddocs-hover-state-layer-opacity));
    --ddocs-on-secondary-container-focus: rgba(211, 227, 253, var(--ddocs-focus-state-layer-opacity));
    --ddocs-on-secondary-container-pressed: rgba(211, 227, 253, var(--ddocs-pressed-state-layer-opacity));
    --ddocs-tertiary: #6dd58c;
    --ddocs-on-tertiary: #0a3818;
    --ddocs-on-tertiary-hover: #64c882;
    --ddocs-on-tertiary-focus: #61c27e;
    --ddocs-on-tertiary-pressed: #61c27e;
    --ddocs-tertiary-container: #0f5223;
    --ddocs-on-tertiary-container: #c4eed0;
    --ddocs-error: #f2b8b5;
    --ddocs-on-error: #601410;
    // missing error container
    // missing on error container
    --ddocs-background: #1f1f1f;
    --ddocs-on-background: #e3e3e3;
    --ddocs-on-background-hover: rgba(227, 227, 227, var(--ddocs-hover-state-layer-opacity)); // Just the state layer.
    --ddocs-on-background-focus: rgba(227, 227, 227, var(--ddocs-focus-state-layer-opacity));
    --ddocs-on-background-pressed: rgba(227, 227, 227, var(--ddocs-pressed-state-layer-opacity));
    --ddocs-surface: #1f1f1f;
    --ddocs-surface-container-low: #28282a; // I’m stealing these from screenshots, so I don’t know the actual surface tint. (I tried to find it.)
    --ddocs-surface-container: #2d2e31;
    --ddocs-surface-container-high: #313336;
    --ddocs-on-surface: #e3e3e3;
    --ddocs-on-surface-disabled: rgba(227, 227, 227, 12%); 
    --ddocs-on-surface-hover: rgba(227, 227, 227, var(--ddocs-hover-state-layer-opacity)); 
    --ddocs-on-surface-focus: rgba(227, 227, 227, var(--ddocs-focus-state-layer-opacity)); 
    --ddocs-on-surface-pressed: rgba(227, 227, 227, var(--ddocs-pressed-state-layer-opacity)); 
    --ddocs-surface-container-highest: #444746; 
    --ddocs-on-surface-variant: #c4c7c5; 
    --ddocs-on-surface-variant-hover: rgba(196, 199, 197, var(--ddocs-hover-state-layer-opacity));
    --ddocs-on-surface-variant-focus: rgba(196, 199, 197, var(--ddocs-focus-state-layer-opacity));
    --ddocs-on-surface-variant-pressed: rgba(196, 199, 197, var(--ddocs-pressed-state-layer-opacity));
    --ddocs-outline: #8e918f;
    --ddocs-outline-variant: #444746;
    --ddocs-inverse-surface: #e3e3e3; // inverse colours taken from the “Signed in as” bar. Might be a relic of m2
    --ddocs-inverse-on-surface: #3c4043;
    --ddocs-inverse-on-surface-hover: #d5d6d6;
    --ddocs-inverse-on-surface-focus: #cfcfd0;
    --ddocs-inverse-on-surface-pressed: #cfcfd0;
    --ddocs-surface-tint: #6750A4; // Definitely not this.
    // State layers (a translucent overlay is placed over things that are hovered, focused, &c.)
    --ddocs-hover-state-layer-opacity: 8%;
    --ddocs-focus-state-layer-opacity: 12%;
    --ddocs-pressed-state-layer-opacity: 12%;
    --ddocs-dragged-state-layer-opacity: 16%;
    // Shape
    --ddocs-corner-none: 0rem;
    --ddocs-corner-xs: 0.25rem;
    --ddocs-corner-s: 0.5rem;
    --ddocs-corner-m: 0.75rem;
    --ddocs-corner-l: 1rem;
    --ddocs-corner-xl: 1.75rem;
    // Shadow
    --ddocs-level2: 0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12);
    --paleblue-icons: hue-rotate(3.6deg) saturate(32.2%) brightness(170%); /* To desaturate blue icons to make them more legible against a dark background. If it is an inline SVG, changing its fill color to palerblue is preferable. */
    --palegreen-icons: hue-rotate(-2deg) saturate(38%) brightness(182%);
    --white-icons: brightness(280%) saturate(10%);
    --whiter-icons: brightness(325%);
    --darkfilter: invert(100%) hue-rotate(180deg) contrast(@document-contrast);
    --on: background-color 0.02s ease-in, border-color 0.06s ease, color 0.05s ease, filter 0.01s ease;
    --off: background-color 0.25s ease, border-color 0.1s ease, color 0.25s ease, filter 0.25s ease;
    // Dark Docs m2 variables (will be removed once side panels and the homepage get Material U’d)
    --palerblue: #8AB4F8; /* For blue text, icons, nearby items that need to be paleblue, and paleblue buttons on hover. */
    --paleblue: #669DF7; /* For blue buttons and other wider areas of paleblue. */
    --blue-ripple: #394457; /* Background color to indicate that something is active (toggled on or being clicked, for example). */
    --palergreen: #81C995; /* Mostly for suggesting mode. */


No reviews yet.