Degoog — Themes

Override look, layout, and result markup.

Default theme reference

The built-in theme lives at src/public/themes/degoog-theme/ — use it as your starting point.

Getting started

Create a folder in data/themes/ (or DEGOOG_THEMES_DIR). The folder name is your theme id. Add a theme.json with at least a name.

Tier What you provide What you control
CSS only theme.json + stylesheet Colours, fonts, spacing via CSS variables
CSS + templates theme.json + stylesheet + template files Above + HTML structure of any section
Layout override theme.json + stylesheet + custom layout.html Above + page title, meta tags, favicons, scripts
Full HTML override theme.json + stylesheet + custom index.html / search.html Total control — bypasses the layout entirely

Only include the templates you want to change — everything else falls back to the default theme. Apply via Settings → Themes → Apply.

Layout override

To customise the page title, meta description, favicons, or anything in the <head>, provide a layout.html in your theme and reference it under html.layout. Copy the default layout and edit it. You must keep these placeholders:

Page architecture

Every page has three layers:

  1. Layout (layout.html) — shared HTML shell. Change at your own risk.
  2. Skeleton (index.html / search.html) — empty <div>s with required IDs. JS depends on these.
  3. Templates — individual HTML files rendered into the skeleton. These are what themes override.

theme.json

See the default theme.json for a complete example.

Key Required Description
name yes Display name in Settings → Themes
author, description, version no Shown on the theme card
css no Stylesheet path (supports .scss). Served at /theme/style.css
templates no Object mapping template keys to file paths. Injected as <template> elements automatically
html no Object with layout, index, search. Fragments are composed into the layout; full HTML documents (starting with <!doctype>) bypass it entirely
settingsSchema no Exposes a Configure button on the theme card. Values stored under theme-<id>

Custom HTML can use these placeholders: __THEME_CSS__, __THEME_ATTRS__, __PLUGIN_ASSETS__, __APP_VERSION__, __THEME_TEMPLATES__, __PAGE_CONTENT__, __BODY_CLASS__.

Static assets

Any file inside your theme folder is served at /themes/<theme-id>/<path>. Supported types: JS, CSS, HTML, JSON, SVG, PNG, JPG, GIF, WebP, TTF, WOFF, WOFF2.

Use this to load custom fonts, images, or scripts from your theme CSS or HTML:

@font-face {
  font-family: "My Font";
  src: url("/themes/my-theme/fonts/my-font.woff2") format("woff2");
  font-display: swap;
}

theme.json is never served.

Example

{
  "name": "My Theme",
  "css": "style.css",
  "templates": {
    "result": "templates/result.html"
  }
}

Templates

Templates control the HTML of every page section. List them under templates in theme.json — keys are auto-prefixed with degoog- to form the element id. The last template with a given id wins, so your overrides take priority over the defaults.

Search page templates

Key Description Source
search-header Logo + search bar + settings gear header.html
search-tabs Tab bar + options dropdown tabs.html
search-media-preview Image / video preview panel media-preview.html
search-lightbox Full-screen image lightbox lightbox.html
result Web / news result item result.html
image-card Image grid card image-card.html
video-card Video grid card video-card.html
at-a-glance At-a-glance box at-a-glance.html

Home page templates

Key Description Source
home-header Top header bar header.html
home-logo Logo / branding logo.html
home-search Search form search.html
home-footer Footer footer.html

Skeleton IDs

Skeleton elements are empty <div>s with only an id. JS injects templates into them. Do not remove or rename these IDs.

Home page

ID Receives
header degoog-home-header
main-home Main content area (plugins may inject here)
home-logo degoog-home-logo
home-search degoog-home-search
home-footer degoog-home-footer

Search page

ID Receives
results-page Top-level wrapper
results-header degoog-search-header
results-tabs degoog-search-tabs
results-meta Engine timing / stats
results-layout Layout wrapper (main + sidebar + preview)
results-main Main results column
at-a-glance degoog-at-a-glance
results-list Search results
pagination Page navigation
sidebar-col Sidebar column
results-sidebar Sidebar content
media-preview-panel degoog-search-media-preview
img-lightbox degoog-search-lightbox
slot-above-results Plugin slot
slot-below-results Plugin slot
slot-above-sidebar Plugin slot
slot-below-sidebar Plugin slot

Required IDs inside templates

Some templates contain inner elements that JS hooks into. Keep these IDs when overriding or the feature breaks. Templates not listed here (degoog-home-header, degoog-home-logo, degoog-home-footer, degoog-result, degoog-image-card, degoog-video-card, degoog-at-a-glance) can be restructured freely.

degoog-home-search

degoog-search-header

degoog-search-tabs

degoog-search-media-preview

degoog-search-lightbox

Placeholder syntax

Inside templates, use double curly braces for dynamic values. All values are HTML-escaped automatically.

Syntax Description
{{ name }} Output a value
{{#if name}} … {{/if name}} Conditional — rendered when truthy
{{#each name}} … {{/each name}} Loop. {{ . }} = item, {{ @index }} = index

{{#if}} blocks must contain balanced HTML. Placeholders work in text and quoted attribute values (href="{{ url }}") but not as tag names.

Placeholders per template

degoog-result

Key Type Description
title string Result title
url string Result URL
cite_url string Display URL (hostname + path)
snippet string Description
favicon_url string Proxied favicon
thumbnail_url string Proxied thumbnail (empty if none)
sources array Engine names
duration string Video duration (empty for non-video)
link_target string _blank or _self
link_rel string noopener or empty

degoog-image-card

Key Type Description
title string Alt text
url string Source page URL
thumbnail_url string Proxied thumbnail
hostname string Source hostname
sources array Engine names

degoog-video-card

Key Type Description
title string Video title
url string Video page URL
thumbnail_url string Proxied thumbnail
hostname string Source hostname
duration string Duration (may be empty)
sources array Engine names

degoog-at-a-glance

Key Type Description
title string Title
url string URL
snippet string Snippet text
sources array Engine names
sources_text string Engine names comma-separated

Quick example

Override just the result template — everything else stays default:

templates/result.html:

<div class="my-result">
  <a href="{{ url }}" target="{{ link_target }}">{{ title }}</a>
  <p>{{ snippet }}</p>
  <small>{{ cite_url }}</small>
  {{#if thumbnail_url}}
  <img src="{{ thumbnail_url }}" loading="lazy">
  {{/if thumbnail_url}}
  {{#each sources}}
  <span class="tag">{{ . }}</span>
  {{/each sources}}
</div>

theme.json:

{
  "name": "My Theme",
  "css": "style.css",
  "templates": {
    "result": "templates/result.html"
  }
}