Skip to content

Custom Themes ​

Add a theme in Admin → Site → Global CSS, save it, and refresh the page. go-drive appends this CSS after the bundled application stylesheet, so a documented selector with equal specificity normally does not need !important.

The theme API has two layers:

  1. Override semantic custom properties for colors, surfaces, radii, shadows, glass effects, and motion.
  2. Use documented data-ui and data-surface selectors only when a particular component needs different treatment.

Internal class names are implementation details and may change.

Color schemes ​

The default theme follows prefers-color-scheme. An absent data-theme attribute means automatic mode; data-theme="light" or data-theme="dark" on the root element forces a built-in scheme.

Use this pattern for automatic light-mode overrides:

css
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    --color-bg-glass: rgba(255, 255, 255, 0.62);
  }
}

Use an attribute selector when a script or integration forces a scheme:

css
:root[data-theme='light'] {
  --color-bg-glass: rgba(255, 255, 255, 0.62);
}

:root[data-theme='dark'] {
  --color-bg-glass: rgba(20, 24, 31, 0.64);
}

Place values shared by both schemes directly on :root.

Theme properties ​

Backgrounds and surfaces ​

PropertyPurpose
--color-bg-canvasPage canvas fallback color
--color-bg-surfaceMain content surface
--color-bg-elevatedRaised, non-glass content
--color-bg-glassTranslucent glass surface
--color-bg-hoverPointer hover state
--color-bg-focusFocused control state
--color-bg-selectedSelected item state
--color-bg-invalidInvalid or rejected state
--color-bg-table-headerTable header surface

Text, fields, and separators ​

PropertyPurpose
--color-textPrimary text
--color-text-mutedSecondary text
--color-text-disabledDisabled or unavailable content
--color-borderGeneral separator
--color-field-bgInput background
--color-field-bg-disabledDisabled input background
--color-field-borderInput border
--color-glass-borderGlass edge highlight

Actions and status ​

--color-accent, --color-success, --color-warning, and --color-danger are suitable for text and icons. Their -strong variants are used for filled controls, with matching foreground properties:

text
--color-accent-strong       --color-on-accent
--color-info-strong         --color-on-info
--color-success-strong      --color-on-success
--color-warning-strong      --color-on-warning
--color-danger-strong       --color-on-danger

Other state properties are:

text
--color-overlay
--color-loading-overlay
--color-focus-ring
--color-progress-track
--color-progress-track-paused
--color-progress-value

Shape, depth, glass, and motion ​

PropertyPurpose
--radius-controlButtons and controls
--radius-popoverDropdowns and menus
--radius-dialogDialog windows
--radius-glassLarge glass surfaces
--radius-glass-compactCompact glass surfaces
--backdrop-filter-fieldInput and editor field blur filter
--backdrop-filter-glassGlass blur and saturation filter
--shadow-controlHovered control shadow
--shadow-elevatedDialog and popover shadow
--motion-duration-fastSmall interaction duration
--motion-duration-normalEnter/leave duration
--motion-easing-standardStandard motion curve
--motion-easing-exitExit motion curve

Use none for --backdrop-filter-field or --backdrop-filter-glass to disable the corresponding filter. A visible blur requires a translucent background color and visual content behind the surface.

Stable component selectors ​

The following attributes are the supported structural theme hooks.

SelectorTarget
[data-ui="app-canvas"]Page canvas (body)
[data-ui="app"]Mounted application
[data-ui="app-header"]Global header
[data-ui="button"]Application button or button-like navigation
[data-ui="explorer"]File explorer
[data-ui="entry-panel"]Main file-list surface
[data-ui="readme"]README surface
[data-ui="readme-content"]README content wrapper
[data-ui="markdown"]Rendered Markdown
[data-ui="path-bar"]Breadcrumb path
[data-ui="path-segment"]Breadcrumb segment
[data-ui="path-link"]Breadcrumb link
[data-ui="search-panel"]Search surface
[data-ui="dropdown"]Dropdown component
[data-ui="dropdown-trigger"]Dropdown trigger
[data-ui="dropdown-panel"]Floating dropdown panel
[data-ui="menu"]Floating entry menu surface
[data-ui="menu-content"]Entry menu contents
[data-ui="menu-item"]Entry menu action
[data-ui="dialog-overlay"]Dialog backdrop
[data-ui="dialog"]Dialog surface
[data-ui="dialog-header"]Dialog header
[data-ui="dialog-body"]Dialog body
[data-ui="dialog-footer"]Dialog actions
[data-ui="admin-page"]Administration layout
[data-ui="handler-header"]Preview or editor title bar
[data-ui="preview"]Preview/editor root
[data-ui="entry-drag-status"]Drag status popup
[data-ui="drop-zone-indicator"]Full-screen upload drop indicator
[data-ui="drop-zone"]Upload drop target
[data-surface="glass"]Any built-in glass surface

State and variant attributes refine these selectors:

css
[data-ui='button'][data-variant='primary'] {}
[data-ui='button'][data-variant='plain'] {}
[data-ui='button'][data-size='compact'] {}
[data-ui='path-segment'][data-root] {}
[data-ui='menu-item'][data-variant='danger'] {}
[data-ui='preview'][data-handler='video'] {}
[aria-disabled='true'] {}
[aria-expanded='true'] {}

Ready-to-use presets ​

These presets support automatic light/dark mode and explicit data-theme="light" / "dark". Expand a preset and use the copy button in the code block, then paste the complete stylesheet into Global CSS.

Paper ​

Warm paper colors, ruled canvas lines, restrained radii, serif typography, ink accents, and offset shadows create a layered stationery appearance.

Show complete paper CSS
css
:root {
  --paper-canvas: #e8dec4;
  --paper-surface: #fffaf0;
  --paper-elevated: #fffdf7;
  --paper-hover: #f2e7ce;
  --paper-focus: #f7ecd3;
  --paper-selected: #ead9b4;
  --paper-invalid: #f2d4c8;
  --paper-text: #332d24;
  --paper-text-muted: #746957;
  --paper-text-disabled: #9a907f;
  --paper-border: #cbbd9c;
  --paper-accent: #8b3f32;
  --paper-accent-strong: #8b3f32;
  --paper-rule: rgba(91, 112, 127, 0.16);
  --paper-margin: rgba(173, 79, 70, 0.2);
  --paper-shadow: rgba(76, 61, 39, 0.26);

  --color-bg-canvas: var(--paper-canvas);
  --color-bg-surface: var(--paper-surface);
  --color-bg-elevated: var(--paper-elevated);
  --color-bg-glass: var(--paper-surface);
  --color-bg-hover: var(--paper-hover);
  --color-bg-focus: var(--paper-focus);
  --color-bg-selected: var(--paper-selected);
  --color-bg-invalid: var(--paper-invalid);
  --color-bg-table-header: var(--paper-hover);
  --color-text: var(--paper-text);
  --color-text-muted: var(--paper-text-muted);
  --color-text-disabled: var(--paper-text-disabled);
  --color-border: var(--paper-border);
  --color-field-bg: var(--paper-elevated);
  --color-field-bg-disabled: var(--paper-hover);
  --color-field-border: var(--paper-border);
  --color-glass-border: var(--paper-border);
  --color-accent: var(--paper-accent);
  --color-accent-strong: var(--paper-accent-strong);
  --color-overlay: rgba(51, 45, 36, 0.48);
  --color-loading-overlay: var(--paper-surface);
  --color-focus-ring: var(--paper-accent);
  --color-progress-track: var(--paper-hover);
  --color-progress-track-paused: var(--paper-selected);
  --color-progress-value: var(--paper-accent);

  --radius-control: 3px;
  --radius-popover: 4px;
  --radius-dialog: 6px;
  --radius-glass: 4px;
  --radius-glass-compact: 3px;
  --backdrop-filter-field: none;
  --backdrop-filter-glass: none;
  --shadow-control: 2px 2px 0 var(--paper-shadow);
  --shadow-elevated: 6px 7px 0 var(--paper-shadow);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --paper-canvas: #1d1a16;
    --paper-surface: #29251f;
    --paper-elevated: #302b24;
    --paper-hover: #383127;
    --paper-focus: #40372b;
    --paper-selected: #51422f;
    --paper-invalid: #50322c;
    --paper-text: #eee2c8;
    --paper-text-muted: #b8aa90;
    --paper-text-disabled: #827866;
    --paper-border: #665a47;
    --paper-accent: #e48d72;
    --paper-accent-strong: #9f4e3d;
    --paper-rule: rgba(151, 174, 185, 0.1);
    --paper-margin: rgba(220, 119, 101, 0.16);
    --paper-shadow: rgba(0, 0, 0, 0.42);
  }
}

:root[data-theme='dark'] {
  --paper-canvas: #1d1a16;
  --paper-surface: #29251f;
  --paper-elevated: #302b24;
  --paper-hover: #383127;
  --paper-focus: #40372b;
  --paper-selected: #51422f;
  --paper-invalid: #50322c;
  --paper-text: #eee2c8;
  --paper-text-muted: #b8aa90;
  --paper-text-disabled: #827866;
  --paper-border: #665a47;
  --paper-accent: #e48d72;
  --paper-accent-strong: #9f4e3d;
  --paper-rule: rgba(151, 174, 185, 0.1);
  --paper-margin: rgba(220, 119, 101, 0.16);
  --paper-shadow: rgba(0, 0, 0, 0.42);
}

[data-ui='app-canvas'] {
  background-color: var(--color-bg-canvas);
  background-image:
    linear-gradient(
      to right,
      transparent 0,
      transparent 52px,
      var(--paper-margin) 52px,
      var(--paper-margin) 53px,
      transparent 53px
    ),
    repeating-linear-gradient(
      to bottom,
      transparent 0,
      transparent 27px,
      var(--paper-rule) 27px,
      var(--paper-rule) 28px
    );
  background-attachment: fixed;
}

[data-ui='app'] {
  font-family: Georgia, 'Noto Serif', 'Noto Serif CJK SC', serif;
}

[data-ui='app-header'] {
  border-bottom: 1px solid var(--paper-border);
}

[data-surface='glass'] {
  outline: 1px solid var(--paper-border);
  outline-offset: -1px;
  box-shadow: var(--shadow-elevated);
}

[data-ui='button'] {
  letter-spacing: 0.02em;
}

[data-ui='app-header'] [data-ui='button'] {
  padding: 4px 8px;
  border-bottom: 1px solid currentColor;
}

:is(
  [data-ui='app-header'] [data-ui='button'],
  [data-ui='button'][data-variant='primary'],
  [data-ui='button'][data-variant='info'],
  [data-ui='button'][data-variant='success'],
  [data-ui='button'][data-variant='warning'],
  [data-ui='button'][data-variant='danger']
):active {
  transform: translate(1px, 1px);
  box-shadow: none;
}

Retro Terminal ​

Phosphor colors, monospaced text, scanlines, square panels, and crisp borders turn the file manager into a restrained command-console display.

Show complete retro terminal CSS
css
:root {
  --terminal-canvas: #e7eadf;
  --terminal-surface: #f4f6ed;
  --terminal-elevated: #fbfcf6;
  --terminal-hover: #dce5d4;
  --terminal-focus: #d3e5cc;
  --terminal-selected: #c7ddbd;
  --terminal-invalid: #ead1cb;
  --terminal-text: #17251a;
  --terminal-muted: #526456;
  --terminal-disabled: #879188;
  --terminal-border: #66806a;
  --terminal-accent: #226b36;
  --terminal-accent-strong: #226b36;
  --terminal-scanline: rgba(34, 107, 54, 0.07);
  --terminal-glow: rgba(34, 107, 54, 0.18);

  --color-bg-canvas: var(--terminal-canvas);
  --color-bg-surface: var(--terminal-surface);
  --color-bg-elevated: var(--terminal-elevated);
  --color-bg-glass: var(--terminal-surface);
  --color-bg-hover: var(--terminal-hover);
  --color-bg-focus: var(--terminal-focus);
  --color-bg-selected: var(--terminal-selected);
  --color-bg-invalid: var(--terminal-invalid);
  --color-bg-table-header: var(--terminal-hover);
  --color-text: var(--terminal-text);
  --color-text-muted: var(--terminal-muted);
  --color-text-disabled: var(--terminal-disabled);
  --color-border: var(--terminal-border);
  --color-field-bg: var(--terminal-elevated);
  --color-field-bg-disabled: var(--terminal-hover);
  --color-field-border: var(--terminal-border);
  --color-glass-border: var(--terminal-border);
  --color-accent: var(--terminal-accent);
  --color-accent-strong: var(--terminal-accent-strong);
  --color-on-accent: #fff;
  --color-overlay: rgba(23, 37, 26, 0.56);
  --color-loading-overlay: var(--terminal-canvas);
  --color-focus-ring: var(--terminal-accent);
  --color-progress-track: var(--terminal-hover);
  --color-progress-track-paused: var(--terminal-selected);
  --color-progress-value: var(--terminal-accent);

  --radius-control: 0;
  --radius-popover: 0;
  --radius-dialog: 0;
  --radius-glass: 0;
  --radius-glass-compact: 0;
  --backdrop-filter-field: none;
  --backdrop-filter-glass: none;
  --shadow-control: 2px 2px 0 var(--terminal-border);
  --shadow-elevated: 4px 4px 0 var(--terminal-border);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --terminal-canvas: #050b07;
    --terminal-surface: #09130c;
    --terminal-elevated: #0c1a10;
    --terminal-hover: #102719;
    --terminal-focus: #12321e;
    --terminal-selected: #164326;
    --terminal-invalid: #351718;
    --terminal-text: #9df7a9;
    --terminal-muted: #64ad70;
    --terminal-disabled: #37643f;
    --terminal-border: #2e8b45;
    --terminal-accent: #72f28a;
    --terminal-accent-strong: #287d3d;
    --terminal-scanline: rgba(114, 242, 138, 0.055);
    --terminal-glow: rgba(114, 242, 138, 0.28);
  }
}

:root[data-theme='dark'] {
  --terminal-canvas: #050b07;
  --terminal-surface: #09130c;
  --terminal-elevated: #0c1a10;
  --terminal-hover: #102719;
  --terminal-focus: #12321e;
  --terminal-selected: #164326;
  --terminal-invalid: #351718;
  --terminal-text: #9df7a9;
  --terminal-muted: #64ad70;
  --terminal-disabled: #37643f;
  --terminal-border: #2e8b45;
  --terminal-accent: #72f28a;
  --terminal-accent-strong: #287d3d;
  --terminal-scanline: rgba(114, 242, 138, 0.055);
  --terminal-glow: rgba(114, 242, 138, 0.28);
}

[data-ui='app-canvas'] {
  background-color: var(--color-bg-canvas);
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 3px,
    var(--terminal-scanline) 3px,
    var(--terminal-scanline) 4px
  );
  background-attachment: fixed;
}

[data-ui='app'] {
  font-family: 'Cascadia Mono', 'SFMono-Regular', Consolas, monospace;
  text-shadow: 0 0 8px var(--terminal-glow);
}

[data-surface='glass'] {
  outline: 1px solid var(--terminal-border);
  outline-offset: -1px;
}

[data-ui='app-header'] {
  border-bottom: 3px double var(--terminal-border);
}

[data-ui='button'] {
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

[data-ui='app-header'] [data-ui='button'] {
  padding: 4px 8px;
  border: 1px solid currentColor;
  background-color: var(--color-bg-surface);
}

[data-ui='path-segment'][data-root] [data-ui='path-link']::before {
  content: '> ';
}

Troubleshooting ​

  • Inspect the element and prefer a documented custom property before adding a structural selector.
  • Avoid !important; it is usually needed only when overriding an inline style or an unusually specific state.
  • If glass looks opaque, reduce the alpha channel of --color-bg-glass.
  • If the background remains sharp, confirm that the element has data-surface="glass" and that --backdrop-filter-glass is not none.
  • A fixed background can cost additional rendering work on mobile browsers. Remove background-attachment: fixed if scrolling becomes uneven.
  • Custom CSS can request external images and fonts. Only use asset URLs you trust.

Released under the MIT License.