Degoog Docs

Degoog Themes

Override the look, layout, and result markup.

Default theme reference

The default theme lives at src/public/themes/degoog-theme/. You should use it as your starting point.

Getting started

Create a folder inside data/themes/ or whatever you set DEGOOG_THEMES_DIR to. The folder name will be your theme ID. Add a theme.json file with at least a name property.

Tier What you provide What you control
CSS only theme.json plus your stylesheet Colors, fonts, and spacing using CSS variables
CSS and templates theme.json plus your stylesheet and template files Everything above plus the HTML structure of any section
Layout override theme.json plus your stylesheet and a custom layout.html Everything above plus the page title, meta tags, favicons, and scripts
Full HTML override theme.json plus your stylesheet and a custom index.html or search.html Total control that bypasses the layout entirely

Only include the templates you actually want to change because everything else will naturally fall back to the default theme. You can apply your new theme by navigating to Settings and then Themes.

Layout override

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

  • __PAGE_CONTENT__ is where the skeleton HTML gets inserted
  • __BODY_CLASS__ is the body class attribute
  • __THEME_TEMPLATES__ is where your templates are injected
  • __THEME_CSS__, __PLUGIN_ASSETS__, __CUSTOM_CSS__, and __APP_VERSION__

Page architecture

Every page is built with three layers:

  1. Layout (layout.html) is the shared HTML shell. Change this at your own risk.
  2. Skeleton (index.html or search.html) provides empty <div> elements with required IDs that our JavaScript relies on.
  3. Templates are individual HTML files rendered directly into the skeleton. These are what your themes will override.

theme.json

Check out the default theme.json for a complete working example.

Key Required Description
name yes The display name shown in Settings then Themes
author, description, version no Details shown on the theme card
css no Your stylesheet path which also supports .scss files. It is served at /theme/style.css
templates no An object mapping your template keys to their file paths. These are injected automatically as <template> elements
html no An object containing layout, index, and search. Fragments are composed into the layout while full HTML documents starting with <!doctype> bypass the layout entirely
settingsSchema no Exposes a Configure button directly on the theme card. These values are stored under theme-<id>

Your custom HTML can utilize these placeholders: __THEME_CSS__, __THEME_ATTRS__, __PLUGIN_ASSETS__, __CUSTOM_CSS__, __APP_VERSION__, __THEME_TEMPLATES__, __PAGE_CONTENT__, and __BODY_CLASS__.

Static assets

Any file placed inside your theme folder is served securely at /themes/<theme-id>/<path>. We support JS, CSS, HTML, JSON, SVG, PNG, JPG, GIF, WebP, TTF, WOFF, and WOFF2 files.

You can use this to load your custom fonts, images, or scripts directly 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;
        }

Note that theme.json is never served to the client.

Example

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

Templates

Templates control the HTML structure of every page section. You list them under templates inside your theme.json file. The keys are automatically prefixed with degoog- to form the element ID. The last template with a specific ID wins, meaning your overrides will always take priority over the defaults.

Search page templates

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

Home page templates

Key Description Source
home-header Top header navigation bar header.html
home-logo Main logo and branding logo.html
home-search The primary search form search.html
home-footer Page footer footer.html

Skeleton IDs

Skeleton elements are simply empty <div> tags that only contain an id. Our JavaScript injects the templates right into them. Please do not remove or rename these IDs.

Home page

ID Receives
header degoog-home-header
main-home Main content area where plugins might inject
home-logo degoog-home-logo
home-search degoog-home-search
home-footer degoog-home-footer

Search page

ID Receives
results-page Top level page wrapper
results-header degoog-search-header
results-tabs degoog-search-tabs
results-meta Engine timing and stats display
results-layout Layout wrapper covering main, sidebar, and previews
results-main Main results column
at-a-glance degoog-at-a-glance
results-list The actual search results
pagination Page navigation controls
sidebar-col Sidebar column container
results-sidebar Sidebar content area
media-preview-panel degoog-search-media-preview
img-lightbox degoog-search-lightbox
slot-above-results Plugin slot area
slot-below-results Plugin slot area
slot-above-sidebar Plugin slot area
slot-below-sidebar Plugin slot area

Required IDs inside templates

Some templates contain inner elements that our JavaScript hooks into directly. Keep these IDs intact when you override files otherwise the feature will break. Any templates not listed here like degoog-home-header, degoog-home-logo, degoog-home-footer, degoog-image-card, degoog-video-card, and degoog-at-a-glance can be restructured freely.

degoog-home-search

  • search-input handles the text input
  • ac-dropdown-home handles the autocomplete dropdown
  • search-bar-actions-home handles the action buttons
  • btn-lucky and lucky-slot-inner handle the lucky animation

degoog-search-header

  • results-search-input handles the search input
  • results-search-btn handles the submit button
  • ac-dropdown-results handles the autocomplete dropdown
  • search-bar-actions-results handles the action buttons
  • .results-logo is the required class for the logo link

degoog-search-tabs

  • .results-tab[data-type] is the class and attribute for the tab buttons
  • tools-bar is the options wrapper
  • tools-toggle is the dropdown toggle
  • tools-dropdown is the dropdown menu
  • tools-submenu-time and tools-submenu-lang handle the filter submenus
  • tools-time-val and tools-lang-val handle the active filter labels
  • tools-lang-filter and tools-lang-list handle the language filter
  • tools-date-from, tools-date-to, and tools-date-apply handle the custom date range

degoog-result

The IDs inside this template are suffixed with the {{ index }} placeholder. This represents the starting position of the result from zero and ensures IDs stay unique across the page. Make sure to keep the prefix intact when you override this.

  • result-favicon-{N} is the favicon image. It must also carry data-favicon-host="{{ favicon_host }}" so JavaScript can attach the fallback chain. During the final fallback phase the <img> is smoothly replaced with a <span class="result-favicon-fallback"> element.
  • result-actions-{N} is the wrapper for per result actions like block, replace, and score. This only renders when show_actions is true.
  • result-actions-toggle-{N} is the button that opens the menu. Its aria-expanded state is toggled by JavaScript.
  • result-actions-menu-{N} is the popover containing the action buttons. It is toggled using the hidden attribute.
  • result-action-block-{N}, result-action-replace-{N}, and result-action-score-{N} are the individual menu buttons. Each one only shows up if its matching action_block, action_replace, or action_score placeholder is active.

degoog-search-media-preview

  • media-preview-close, media-preview-prev, and media-preview-next are the navigation buttons
  • media-preview-img is the main preview image
  • media-preview-info is the sidebar info panel

degoog-search-lightbox

  • img-lightbox-bg is the dark backdrop
  • img-lightbox-close is the close button
  • img-lightbox-wrap is the container for the image
  • img-lightbox-img is the full size image element

Placeholder syntax

Inside your templates you can use double curly braces for dynamic values. Every value gets HTML escaped automatically for security.

Syntax Description
{{ name }} Outputs a value
{{#if name}} content {{/if name}} Conditional block that renders when the value is truthy
{{#each name}} content {{/each name}} Looping block where {{ . }} is the item and {{ @index }} is the index

Your {{#if}} blocks must contain balanced HTML. Placeholders work perfectly in regular text and quoted attribute values like href="{{ url }}" but you cannot use them as HTML tag names.

Placeholders per template

degoog-result

Key Type Description
index number The index starting at zero for this result. This is used to suffix the required IDs in the template.
title string The result title
url string The result URL
cite_url string The display URL showing the hostname and path
snippet string The text description
favicon_url string The proxied favicon. This is just the first candidate before the fallback chain runs in JavaScript.
favicon_host string The hostname used by the favicon fallback chain
thumbnail_url string The proxied thumbnail which is empty if none exists
sources array The engine names
duration string The video duration which is empty for non video results
link_target string Either _blank or _self
link_rel string Either noopener or completely empty
show_actions boolean Returns true when the per result block, replace, or score menu should render. This requires being authenticated on a private instance with at least one action enabled in settings.
action_block boolean Shows the block domain menu item
action_replace boolean Shows the replace domain menu item
action_score boolean Shows the score domain menu item

degoog-image-card

Key Type Description
title string The alt text
url string The source page URL
thumbnail_url string The proxied thumbnail
hostname string The source hostname
sources array The engine names

degoog-video-card

Key Type Description
title string The video title
url string The video page URL
thumbnail_url string The proxied thumbnail
hostname string The source hostname
duration string The video duration which might be empty
sources array The engine names

degoog-at-a-glance

Key Type Description
title string The title
url string The URL
snippet string The snippet text
sources array The engine names
sources_text string The engine names separated by commas

Quick example

Here is how you can override just the result template while keeping everything else as the 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"
          }
        }