Release GitComet Professional launches 28d 06h 25m 04s

Join the waitlist for the early-adopter price Join waitlist

Themes Custom Themes

Custom Themes

Custom theme JSON format, supported fields, and theme file locations.

GitComet loads custom themes from JSON bundle files in your per-user themes directory.

Theme files use schema version 2. A file without a schema_version is rejected outright — see Migrating from the older format if you wrote a theme before this schema landed.

Theme File Location

GitComet creates the user themes directory on startup and only loads custom .json files from that location:

PlatformThemes directory
Linux$XDG_DATA_HOME/gitcomet/themes or ~/.local/share/gitcomet/themes
macOS~/Library/Application Support/gitcomet/themes
Windows%LOCALAPPDATA%\gitcomet\themes or %APPDATA%\gitcomet\themes

Built-in themes are embedded in the GitComet binary and are not written into this directory, so it is yours alone.

Use Open custom theme folder under Settings → GeneralTheme to locate it from the app.

JSON Schema

Disclaimer: The theme JSON format may change as GitComet's UI is still actively being developed.

Each theme file is a bundle with a bundle name and one or more themes. The example below includes every currently supported field. You can save this example directly as a .json file; optional fields are explained below.

{
  "schema_version": 2,
  "name": "My Theme Pack",
  "author": "Example Author",
  "themes": [
    {
      "key": "my_theme_dark",
      "name": "My Theme Dark",
      "appearance": "dark",
      "colors": {
        "surface": {
          "canvas": "#10131aff",
          "chrome": "#171b24ff",
          "panel": "#171b24ff",
          "raised": "#1d2230ff",
          "input": "#202633ff"
        },
        "foreground": {
          "primary": "#edf1f7ff",
          "secondary": "#9ea7b8ff",
          "disabled": { "hex": "#9ea7b8ff", "alpha": 0.62 },
          "placeholder": "#ffffff59",
          "emphasis": "#ffffffff"
        },
        "stroke": {
          "subtle": "#ffffff14",
          "default": "#2c3445ff",
          "control": "#556176ff"
        },
        "interaction": {
          "hover_overlay": { "hex": "#edf1f7ff", "alpha": 0.07 },
          "pressed_overlay": { "hex": "#edf1f7ff", "alpha": 0.11 },
          "hover_background": "#222839ff",
          "pressed_background": "#3a4560d9",
          "selected_background": "#262c3bff",
          "selected_foreground": "#edf1f7ff",
          "selected_indicator": "#59b7ffff",
          "focus_ring": "#59b7ffff",
          "focus_background": { "hex": "#59b7ffff", "alpha": 0.16 }
        },
        "accent": {
          "foreground": "#59b7ffff",
          "solid": "#59b7ffff",
          "on_solid": "#08111cff",
          "subtle_background": "#183246ff"
        },
        "status": {
          "info": { "foreground": "#59b7ffff", "background": "#183246ff", "border": "#387ba7ff" },
          "success": { "foreground": "#9edb63ff", "background": "#20351fff", "border": "#59823fff" },
          "warning": { "foreground": "#ffc06aff", "background": "#3b2d1bff", "border": "#98713eff" },
          "danger": { "foreground": "#f16b73ff", "background": "#3b1d24ff", "border": "#95434aff" }
        },
        "editor": {
          "background": "#10131aff",
          "foreground": "#edf1f7ff",
          "gutter_background": "#10131aff",
          "line_number": "#9ea7b8ff",
          "cursor": "#edf1f7c7",
          "selection_background": "#59b7ff47",
          "search_match_background": "#3b2d1bff",
          "search_match_foreground": "#ffc06aff",
          "bracket_match_background": "#ffffff26",
          "occurrence_highlight_background": "#59b7ff26",
          "indent_guide": "#ffffff14"
        },
        "diff": {
          "added": { "foreground": "#b9f2c0ff", "background": "#163322ff", "word_background": "#b9f2c038", "focused_background": "#b9f2c033" },
          "removed": { "foreground": "#ffc4ccff", "background": "#40171dff", "word_background": "#ffc4cc38", "focused_background": "#ffc4cc33" },
          "modified": { "foreground": "#ffc06aff", "background": "#3b2d1bff", "word_background": "#ffc06a38", "focused_background": "#ffc06a33" }
        },
        "tooltip": { "background": "#0b0e14ff", "foreground": "#f5f7fbff" },
        "scrollbar": {
          "thumb": { "hex": "#9ea7b8ff", "alpha": 0.30 },
          "thumb_hover": { "hex": "#9ea7b8ff", "alpha": 0.42 },
          "thumb_pressed": { "hex": "#9ea7b8ff", "alpha": 0.52 }
        },
        "shadow": "#000000ff",
        "graph_lane_palette": [
          "#ff6b6bff",
          "#ffd166ff",
          "#06d6a0ff",
          "#4dabf7ff"
        ],
        "graph_lane_hues": [
          0.00,
          0.18,
          0.42,
          0.63
        ]
      },
      "syntax": {
        "comment": "#7f8aa1ff",
        "comment_doc": "#91a0b8ff",
        "string": "#ffd27aff",
        "string_escape": "#8ce3b4ff",
        "string_regex": "#ff9b8dff",
        "string_special": "#ffc776ff",
        "keyword": "#7ec5ffff",
        "keyword_control": "#8fd8ffff",
        "preproc": "#71d8ffff",
        "number": "#9edb63ff",
        "boolean": "#b4e07aff",
        "function": "#78c4ffff",
        "function_method": "#87d0ffff",
        "function_special": "#96dbffff",
        "constructor": "#5cd7c7ff",
        "type": "#ffc06aff",
        "type_builtin": "#ffce87ff",
        "type_interface": "#ffd9a3ff",
        "namespace": "#9cc1ffff",
        "variable": "#f3f6fbff",
        "variable_parameter": "#c7d0deff",
        "variable_special": "#70c5ffff",
        "variable_builtin": "#78d8cbff",
        "property": "#66c2ffff",
        "label": "#c1b4ffff",
        "constant": "#9edb63ff",
        "constant_builtin": "#bfe68bff",
        "operator": "#c5ceddff",
        "punctuation": "#b4beceff",
        "punctuation_bracket": "#c2cadaff",
        "punctuation_delimiter": "#a9b4c7ff",
        "punctuation_special": "#8fd8ffff",
        "punctuation_list_marker": "#ff9b8dff",
        "tag": "#ffc06aff",
        "attribute": "#74caffff",
        "markup_heading": "#8fd8ffff",
        "markup_link": "#7ec5ffff",
        "text_literal": "#ffd27aff",
        "diff_plus": "#9edb63ff",
        "diff_minus": "#ff9b8dff",
        "diff_delta": "#7ec5ffff",
        "lifetime": "#80d2ffff"
      },
      "radii": {
        "panel": 12.0,
        "pill": 999.0,
        "row": 8.0,
        "control": 8.0,
        "popover": 10.0,
        "window": 12.0
      }
    }
  ]
}

In normal use, provide either graph_lane_palette or graph_lane_hues. The example shows both only so every supported field is visible in one place.

One file can define multiple themes. Theme keys must be unique within the file.

Required Theme Fields

Each entry in themes must include:

FieldTypeNotes
keystringStable internal identifier used in settings and persistence
namestringUser-facing label shown in the UI
appearancestringMust be light or dark
colorsobjectTheme color definitions
radiiobjectRadius values for UI surfaces

The bundle root supports:

FieldTypeNotes
schema_versionnumberRequired. Must be 2
namestringRequired. Bundle name
authorstringOptional
themesarrayRequired. One or more theme entries

Colors Schema

Schema v2 groups colors semantically. Define every group and field below: a token your file leaves out falls back to the bundled theme matching your appearance (gitcomet_dark or gitcomet_light), which keeps older files loading as new tokens are added, but means the omitted token is not yours to control. A token you misspell is still an error — the file is rejected rather than half-applied.

  • surface: canvas, chrome, panel, raised, input
  • foreground: primary, secondary, disabled, placeholder, emphasis
  • stroke: subtle, default, control
  • interaction: hover_overlay, pressed_overlay, hover_background, pressed_background, selected_background, selected_foreground, selected_indicator, focus_ring, focus_background
  • accent: foreground, solid, on_solid, subtle_background
  • status: info, success, warning, danger; each contains foreground, background, and border
  • editor: background, foreground, gutter_background, line_number, cursor, selection_background, search_match_background, search_match_foreground, bracket_match_background, occurrence_highlight_background, indent_guide
  • diff: added, removed, modified; each contains foreground, background, word_background, and focused_background
  • tooltip: background, foreground
  • scrollbar: thumb, thumb_hover, thumb_pressed
  • shadow
  • graph_lane_palette and graph_lane_hues are optional

surface.canvas is the central content area. surface.chrome is the surrounding title/action/sidebar/status band. Necessary input and button outlines should use stroke.control; stroke.subtle is for decorative separators.

Color value format

Most color fields accept either:

  • a hex RGBA string such as #0d1016ff
  • an object with hex plus alpha, for example { "hex": "#5ac1feff", "alpha": 0.60 }

Use graph_lane_palette for an explicit list of colors, or graph_lane_hues for a list of hue values that GitComet turns into graph lane colors automatically.

Syntax colors, graph lanes, and the optional radius fields have fallbacks of their own — omitting graph_lane_palette and graph_lane_hues generates lane colors for your appearance rather than copying the bundled theme's. Every other semantic UI color falls back to the bundled theme for your appearance. Spell them all out anyway: a component never infers a status, editor, selection, or control color from an unrelated token, so an omitted one is a bundled color sitting in your theme, not a shade of it.

editor.occurrence_highlight_background colors other occurrences of a clicked name. It is separate from search matches and bracket matching. Older custom bundles may omit it and inherit the bundled color for their appearance, like other semantic UI colors.

Syntax Schema

The syntax object is optional. Supported keys are:

comment, comment_doc, string, string_escape, string_regex, string_special, keyword, keyword_control, preproc, number, boolean, function, function_method, function_special, constructor, type, type_builtin, type_interface, namespace, variable, variable_parameter, variable_special, variable_builtin, property, label, constant, constant_builtin, operator, punctuation, punctuation_bracket, punctuation_delimiter, punctuation_special, punctuation_list_marker, tag, attribute, markup_heading, markup_link, text_literal, diff_plus, diff_minus, diff_delta, lifetime

Use type in JSON for the main type-name color.

Radii Schema

The radii object is required and must include:

  • panel — cards and panels
  • pill — round badges and chips
  • row — list rows

It may also include (falling back to built-in defaults when omitted):

  • control — buttons, inputs, and tabs (default 8.0)
  • popover — menus, popovers, and dialogs (default 10.0)
  • window — the window frame under client-side decorations (default 12.0)

These values are numeric and control the corner radius used by major UI elements.

Migrating From The Older Format

Theme files written before schema v2 used a single flat colors object (window_bg, text_muted, diff_add_bg, and so on). Those files no longer load. Two things changed:

  1. schema_version is now required. Without it GitComet reports missing schema_version; expected 2 and skips the file. This check runs before anything else, so it is the first error you will see even if the rest of the file also needs updating.
  2. Colors moved into semantic groups. A flat token is not renamed so much as replaced by a more specific one, and several became objects.

The closest v2 equivalents:

v1 tokenv2 location
window_bgsurface.canvas
surface_bgsurface.chrome and surface.panel
surface_bg_elevatedsurface.raised
active_sectioninteraction.selected_background
borderstroke.default
hoverinteraction.hover_background
activeinteraction.pressed_background
focus_ringinteraction.focus_ring
focus_ring_bginteraction.focus_background
textforeground.primary
text_mutedforeground.secondary
input_placeholderforeground.placeholder
emphasis_textforeground.emphasis
accentaccent.foreground and accent.solid
accent_textaccent.on_solid
danger, warning, successstatus.danger, status.warning, status.success — each now an object with foreground, background, and border
diff_add_bg, diff_add_textdiff.added.background, diff.added.foreground
diff_remove_bg, diff_remove_textdiff.removed.background, diff.removed.foreground
tooltip_bg, tooltip_texttooltip.background, tooltip.foreground
scrollbar_thumbscrollbar.thumb
scrollbar_thumb_hoverscrollbar.thumb_hover
scrollbar_thumb_activescrollbar.thumb_pressed

Groups with no v1 equivalent at all — editor, diff.modified, status.info, stroke.subtle, stroke.control, interaction.hover_overlay, interaction.pressed_overlay, interaction.selected_foreground, interaction.selected_indicator, accent.subtle_background, and shadow — have to be chosen rather than converted. Until you do, they come from the bundled theme for your appearance.

Overrides And Validation Behavior

  • Built-in system themes stay embedded in the GitComet binary and are not loaded from the custom themes directory.
  • GitComet loads custom .json files from the themes directory, but ignores files whose basename matches a bundled system theme file such as gitcomet.json.
  • Custom themes can add new theme keys, but they cannot override built-in system theme keys. Any runtime theme entry that reuses a built-in key is ignored.
  • A file that cannot be read or parsed is ignored and reported with its path and reason.
  • GitComet validates the structure and types of custom themes, but does not measure, warn about, reject, or alter their colors based on contrast.
  • GitComet does not expose a separate machine-readable JSON Schema file today; the theme implementation is the source of truth.

Documentation

Search

move open Esc close

Browse the docs or start typing to filter results.