Skip to content

Features

The source code of CSS Loader can be found here

Simple Themes

Requires Manifest Version 1+

Themes are folders with CSS files and a single theme.json file inside. The theme.json determines how everything will be displayed and any options if the theme has them. The CSS Loader loads themes from /home/deck/homebrew/themes.

SimpleTheme

Here is an example.

For a simple theme, the theme.json should look something like this.

{
  "name": "Theme Title",
  "author": "GitHubUsername",
  "target": "Library",
  "manifest_version": 8,
  "description": "This is an example description.",
  "version": "v1.0",
  "inject": {
    "shared.css": ["SP"]
  }
}
  • The name element describes the theme name. This is also used as the folder name for the theme store.
  • The author element describes the theme author.
  • An optional version field can be added. If no version field is found, the version defaults to v1.0.
  • The manifest version tells the CSS Loader which version of themes.json you are using. The current version is 8.
  • An optional description can be added to show a text description in the theme store.
  • The inject tab is a dictionary of relative CSS file paths as keys, and a list of tabs you want the CSS to be injected into.
  • The target field describes what part of the UI your theme themes. This is only useful for submitting a theme. The following options are available, but more can be added by creating an issue on github:

Finding which tabs to inject to

CSS Loader has multiple ways of identifying which tab css should be injected to. A tab in this context refers to a virtual window, if you'd like to explore this, see the CEF Debugger

{
  "inject": {
    "shared.css": ["SP"]
  }
}

Specifically, which tab is "SP"?

Injection via Tab name match

cef-tab-names.png

CSS Loader can inject css by the names of tabs. In the screenshot above, entering "Steam Big Picture Mode" as tab would inject into a tab named exactly Steam Big Picture Mode

CSS Loader can also regex match tabs, if tab names are a little more dynamic. For example, in the screenshot above, QuickAccess_uid82 has numbers at the end that change every time Big Picture Mode is launched. To remedy this, "QuickAccess.*" can be used as tab name, which injects into the first tab starting with QuickAccess

CSS Loader v1.7.0

On manifest version 6 or below, or CSS Loader v1.6.x or below, one entry in the tabs list of a css file will always inject into either zero or one tabs. This becomes problematic if for example, two tabs are visible with the same name. Manifest version 7 or CSS Loader v1.7.0+ fixes this and allows to inject into multiple tabs using one named entry.

Injection via Tab URL match

Requires CSS Loader v1.5.0+

cef-json-list

CSS Loader can also inject css by a part of the internal URL used by Valve. A prime example for this would be the Steam store, as its tab name changes to the name of the game being viewed. The internal URL always contains https://store.steampowered.com/. A tab match can be constructed by writing the part of the URL between ~, as example: "~https://store.steampowered.com/~".

Complex Themes

Requires Manifest Version 2+

ComplexTheme

Here is an example.

A complex theme is a theme with patches. Patches are menus that apply additional CSS depending on the selection. The theme.json for a complex theme should look something like this.

{
  "name": "Colored Toggles",
  "version": "v1.2",
  "author": "SuchMeme",
  "target": "System-Wide",
  "description": "this is an example description",
  "manifest_version": 2,
  "inject": {
    "shared.css": ["QuickAccess", "SP", "MainMenu"]
  },
  "patches": {
    "Theme Color": {
      "default": "Orange",
      "type": "dropdown",
      "values": {
        "Orange": {},
        "Lime": {
          "colors/lime.css": ["QuickAccess", "SP", "MainMenu"]
        },
        "Red": {
          "colors/red.css": ["QuickAccess", "SP", "MainMenu"]
        },
        "Magenta": {
          "colors/magenta.css": ["QuickAccess", "SP", "MainMenu"]
        },
        "Gradient RGB": {
          "colors/gradient_rgb.css": ["QuickAccess", "SP", "MainMenu"]
        },
        "Gradient Deck": {
          "colors/gradient_deck.css": ["QuickAccess", "SP", "MainMenu"]
        }
      }
    }
  }
}

The patches section is a dictionary of patch names as key. The value is a dictionary where keys are it's options and their value is the applied CSS, similar to the "inject" section. The special key "default" is required to indicate a default option.

Patches allow for choosing between a dropdown, a checkbox (toggle), or a slider for patch selection using the type field.

Requires Manifest Version 2+

"type": "dropdown"

This is the default value. This type gives a dropdown of all keys in the values dictionary. Choosing an option injects only the CSS specified within the selected value.

dropdown

Slider

Requires Manifest Version 2+

"type": "slider"

This type gives a slider with the labels of the points of all keys in the values dictionary. Choosing an option injects only the CSS specified within the selected value.

slider

Checkbox (Toggle)

Requires Manifest Version 2+

"type": "checkbox"

This type represents the values field as a toggle. This type is unique in the sense that it limits what options you can put in the values dictionary. You need to have a Yes and a No option in the values dictionary, otherwise, the type falls back to a dropdown. When the toggle is on, Yes is selected, otherwise, No is selected.

checkbox

None

Requires Manifest Version 3+

"type": "none"

Displays an arrow with the patch name. Has no functional use. For use with components.

Additional Features

Local Files

You can access files locally from CSS if you use the correct URL. You can access files like fonts, images, and more by using the following URL.

/themes_custom/{your_theme_name}/{image_path}

Here is an example.

Adding Dependencies

Requires Manifest Version 3+

Dependencies are useful if you want to bundle another theme or want to make small modifications to an existing theme. All dependencies get enabled alongside your theme.

In the themes.json file, specify a field called "dependencies". This is a dictionary in which the keys are the name of the theme you want to be dependencies, with their values being another dictionary. This dictionary's keys are the name of any patch this theme has, and the value is the name of a value in the patch. If you don't want to modify any patch value, write {} as the value.

"dependencies": {
    "Switch Like Home": {
        "No Friends": "Yes"
    },
    "Clean Gameview": {}
}

If a theme has a dependencies field like the one above, it will enable both Switch Like Home and Clean Gameview. Switch Like Home's 'No Friends' patch gets forced to 'Yes'.

Here is an example.

Components

Components are a way to attach extra parts to a selectable patch option. Inside a patch, you can make a "components" field (its value is a list), and put the components inside.

Color Picker

Requires Manifest Version 3+

Color picker

Here is an example.

The color picker component injects a CSS variable with a user-specified color.

"components": [
    {
        "name": "Background Picker",
        "type": "color-picker",
        "on": "_",
        "default": "#000",
        "css_variable": "test-main-color",
        "tabs": ["QuickAccess"]
    }
]
  • name refers to the name of the component shown to the user
  • type refers to the type of component
  • on refers to what patch value the component should be displayed on
  • default refers to what default hex color the color picker should default to
  • css_variable refers to the name of the CSS variable that will be injected
  • tabs refers to what tabs the CSS variable will be injected into

Image Picker

Requires Manifest Version 4+

imagepicker

Here is an example.

The image picker component injects a user-supplied file using a file picker into a CSS variable as url(path/to/file). Only files from ~/homebrew/themes can be selected.

"components": [
    {
        "name": "Image Picker",
        "type": "image-picker",
        "on": "_",
        "default": "ThemeName/background.jpg",
        "css_variable": "test-main-image",
        "tabs": ["SP"]
    }
]
  • name refers to the name of the component shown to the user
  • type refers to the type of component
  • on refers to what patch value the component should be displayed on
  • default refers to what default file path the image picker should default to (relative to ~/homebrew/themes)
  • css_variable refers to the name of the CSS variable that will be injected
  • tabs refers to what tabs the CSS variable will be injected into

CSS Variables

Requires Manifest Version 5+

Instead of creating a single file that just stores 1 css variable, a shorthand is available to do it directly in the theme.json.

"inject": {
  "shared.css": ["SP"],
  "--my-cool-css-var": ["#FFF", "SP"]
}

By putting 2 dashes in front of a key in any inject section, CSS Loader will read the first variable of the key's value, and inject that into the remaining array elements as tabs.

Feature Flags

Requires Manifest version 6+

Flags manipulate how a theme is intepreted by CSS Loader. This is used to enable specific niche functionality. There are currently 3 flags

  • PRESET: Handles the theme as a preset. Please do not add this flag manually
  • KEEP_DEPENDENCIES: Added to emulate old behaviour. If this flag is present, when a theme with dependencies is disabled it's dependencies are not disabled.
  • OPTIONAL_DEPENDENCIES: Shows a modal when enabling a theme with this flag present. This modal asks the user if they want to enable the theme, it's dependencies and configure the dependencies.
  • REQUIRE_NAV_PATCH: Forces patching the SteamUI controller navigation. See below for more details.

In theme.json:

"flags": [
  "PRESET",
  "KEEP_DEPENDENCIES",
  "OPTIONAL_DEPENDENCIES",
  "REQUIRE_NAV_PATCH"
],

Tab mappings

Requires Manifest version 7+

To avoid copy pasting the same tabs over and over, manifest v7 introduces a feature called tab mappings. This allows you to create custom definitions for tabs that will get replaced with the tabs defined in a tab mapping

"tabs": {
    "custom_name": ["Steam Big Picture Mode", "MainMenu.*"]
},
"inject": {
    "shared.css": ["custom_name"],
    "shared2.css": ["custom_name"]
}

The above will inject shared.css and shared2.css into the Steam Big Picture Mode and MainMenu tabs.

"tabs": {
    "default": ["Steam Big Picture Mode", "MainMenu.*"]
},
"inject": {
    "shared.css": [],
    "shared2.css": []
}

A special tab mapping name called "default" can be used to create a custom default when no tabs are specified. This will result in the same behaviour as the first example.

Requires Manifest version 9+

When using display: none on elements, sometimes these hidden elements are still selectable by the controller navigation. The 'Nav Patch' fixes this by checking for display: none; on .Focusable elements, and skipping those in the controller navigation routine.

You can enable this by putting REQUIRE_NAV_PATCH in your theme's flags.

Renaming themes

Requires Manifest version 9+

The name attribute in the theme.json has been used in store submissions to name the theme's folder as well. This makes it tricky to change the name of the theme, as it's folder also changes. It's essentially treated as a new theme.

Manifest v9 solves this by introducing the display_name attribute. This attribute allows you to set the name that is displayed to users, while keeping the folder name the same.

{
    "name": "My epic theme",
    "display_name": "My epic theme special edition"
}

Multiple targets

Requires Manifest version 9+

On the DeckThemes site it has always been enforced that a theme could only use a single target. Since manifest v9 it is possible to specify a JSON array of targets. This makes marking a theme with multiple targets possible.

{
    "name": "My epic theme",
    "target": ["Home", "Library"]
}

File watcher

Requires CSS Loader version 1.4.0+

If a file called WATCH is detected in the themes folder, CSS Loader will start watching file changes to any css file in any theme directory. This may lead to buggy behavior, so it's not enabled by default. This means that if any css file gets edited remotely, CSS Loader will automatically reload all themes, so you can 'live edit' css files.

Updated in CSS Loader version 1.9.0+

This feature can now be enabled from the settings menu of CSS Loader, under the name Live CSS Editing

Load Order

Requires CSS Loader version 1.6.2+

CSS Loader normally tries its best to load themes in such a way that they don't conflict with eachother. Sometimes however, it may be preferable to set load order manually.

You can set the load order by creating a file called PRIORITY in the folder of a theme. Inside this priority file a number should be written, indicating the load order. A larger number gives more effective priority. A positive value gives more priority to the theme, a negative value gives less priority to the theme.