Themes
By default, fx draws its interface and code in shades of gray with blue links, and it shows diffs without green or red. A theme changes these colors. Choose one of the two built-in themes, or load a theme file that you write or take from VS Code.
Click the theme name to try the next theme. Only fx-dark and fx-light come with fx. The others approximate themes you add yourself.
fx ships two themes, fx-dark and fx-light, which you select with dark and light. Every other theme comes from a file that you add, as described in Add a theme.
Choose a theme
Set theme in ~/.fx/settings.json, or run fx config set from a terminal:
fx config set theme github-darktheme takes one of three kinds of value:
| Value | Result |
|---|---|
| Not set | fx follows the terminal's light or dark mode and switches when the terminal does. |
"light" or "dark" | fx uses that built-in theme and ignores the terminal's mode. |
A name, such as "github-dark" | fx loads ~/.fx/themes/github-dark.json, a file you add. Leave off .json. |
Run fx config unset theme to return to the default. To try a theme for one run, set FX_THEME, which takes the same values and overrides the setting:
FX_THEME=github-dark fxA project's .fx.json can't set a theme. Setting NO_COLOR turns color off whatever the theme says; see environment variables.
With no theme set, fx asks the terminal for its background color to learn whether it is light or dark. If the terminal doesn't answer, fx reads COLORFGBG when it is set, and otherwise assumes a dark terminal. A theme can't change your terminal's own background. It sets the colors fx draws on top of it.
Setting light or dark, or naming a theme, also turns on green and red line numbers and signs in diffs. With no theme set, fx draws diffs in gray.
Add a theme
fx loads named themes from ~/.fx/themes/. Save a theme file there as <name>.json, then set theme to <name>. A name has 1 to 64 letters, digits, hyphens, underscores, or periods, and the file can be up to 1 MiB.
fx reads two file formats and detects which one a file uses:
- fx's own format, described in Write a theme.
- VS Code color themes, described in Use a VS Code theme.
fx loads a theme file when it starts and again when the terminal switches between light and dark. After you edit a file, restart fx to see the change.
Write a theme
This file, saved as ~/.fx/themes/midnight.json, changes links, inline code, warnings, diffs, and code colors:
{
"type": "dark",
"colors": {
"link": "#58A6FF",
"inline_code": "#A5D6FF",
"warning": "#D29922",
"diff_added": "#3FB950",
"diff_removed": "#F85149",
"diff_added_marker": "#3FB950",
"diff_removed_marker": "#F85149"
},
"syntax": {
"keyword": "#FF7B72",
"string": "#A5D6FF",
"number": "#79C0FF",
"comment": { "fg": "#8B949E", "italic": true },
"function": "#D2A8FF",
"variable": "#FFA657",
"operator": "#FF7B72"
}
}
Select it with fx config set theme midnight.
Every key is optional. A slot that the file leaves out keeps the built-in color for the file's type, so a short file changes only what it names. fx ignores slot names it doesn't know, as long as the value is a valid color, so a file written for a newer fx still loads.
| Key | Value |
|---|---|
type | "dark" or "light". Default: "dark". Selects the built-in theme that supplies omitted slots and the terminal mode the theme is for. See Light and dark variants. |
colors | An object that maps interface slots to colors. |
syntax | An object that maps code slots to colors, or false to turn syntax highlighting off. |
Colors
A color is a hex string such as "#58A6FF" or "#5AF", or an object with these fields:
| Field | Value |
|---|---|
fg | Text color as a hex string. |
bg | Background color as a hex string. |
bold | true or false. |
italic | true or false. |
An object needs fg or bg. An fx theme file can't use hex colors with an alpha channel, such as "#58A6FFCC". In a terminal without 24-bit color, fx uses the nearest of the 256 standard terminal colors.
Several slots are bold in the built-in themes. A plain hex string sets only the color and drops the bold, so write { "fg": "#58A6FF", "bold": true } to keep it.
Interface slots
Put these in colors.
| Slot | Colors |
|---|---|
link | Links in replies. |
inline_code | Inline code in replies. |
dim | Secondary text, such as unchanged lines in a diff. |
hint | Hint text, such as the welcome message and the note after a cancelled tool call. |
statusline | The status line and detail rows in approval panels. |
divider | Rules and separators in menus and review screens. |
tag | Titles in approval panels. Bold by default. |
subtitle | Subtitles in menus. Bold by default. |
selected_completion | The selected entry in a menu. Bold by default. |
approval_button_inactive | The highlight behind the selected row in pickers, such as the @ file finder. |
system_notice_label | The label of a system notice. Bold by default. |
system_notice_text | The text of a system notice. |
warning | Warnings, and cancelled or deferred tool calls. |
green | Success notices. |
red | Error notices. |
diff_added, diff_removed | The text of added and removed lines in a diff. |
diff_added_marker, diff_removed_marker | The line numbers and signs of added and removed lines. Each takes one hex color, with no bg, bold, or italic. Shown only when a theme is selected. |
permission_auto | The auto permission mode in the status line. |
user_card_marker | The rail beside your prompts in the transcript. |
user_card_accent | Accents in your prompt cards. |
task_completed | The marker on completed task-list items in replies. |
tool_stdout, tool_stderr | Standard output and standard error lines in expanded command output. |
Code slots
Put these in syntax. They color code blocks in replies and shell commands in tool calls.
| Slot | Colors |
|---|---|
keyword | Language keywords. |
string | Strings. |
number | Numbers. |
comment | Comments. |
function | Command names in shell commands. |
variable | $VAR, ${VAR}, and ~ in shell commands. |
operator | &&, redirects, pipes, and glob stars in shell commands. |
Use a VS Code theme
fx reads a VS Code color theme as it is. Save the theme's JSON file in ~/.fx/themes/, for example as github-dark.json, and set theme to its name. fx treats a file as a VS Code theme when it has a tokenColors array, or a colors object with a key that contains a period, such as editor.background.
Before you save the file, remove any comments and trailing commas. fx reads strict JSON. fx doesn't follow include, so if a theme inherits from another file, save a merged copy.
fx maps the theme's workbench colors onto its own slots. In this table, the editor foreground is editor.foreground, then foreground. Each row uses the first key that the theme defines.
| fx slots | VS Code colors |
|---|---|
link | textLink.foreground only. Without it, links keep the built-in color. |
inline_code | terminal.ansiCyan, then the editor foreground. |
green, red | terminal.ansiGreen and terminal.ansiRed. |
task_completed | terminal.ansiGreen, then the editor foreground. |
diff_added, diff_added_marker | editorGutter.addedBackground, then terminal.ansiGreen. |
diff_removed, diff_removed_marker | editorGutter.deletedBackground, then terminal.ansiRed. |
warning | editorWarning.foreground, then terminal.ansiYellow. |
divider | editorLineNumber.foreground, then panel.border. |
dim | editorLineNumber.foreground, then the editor foreground. |
statusline | statusBar.foreground, then the editor foreground. |
tool_stdout | terminal.foreground, then the editor foreground. |
tool_stderr | editorWarning.foreground, then terminal.foreground. |
approval_button_inactive | editor.lineHighlightBackground behind the editor foreground. |
hint, tag, subtitle, selected_completion, system_notice_label, system_notice_text, permission_auto, user_card_marker, user_card_accent | The editor foreground. |
Code colors come from the theme's tokenColors. For each code slot, fx picks the best matching entry for these scopes:
| Slot | Scope |
|---|---|
keyword | keyword |
string | string |
number | constant.numeric |
comment | comment |
function | entity.name.function |
variable | variable |
operator | keyword.operator |
An exact scope beats a prefix match, and a later entry beats an earlier one with the same match. fx skips compound scopes, which contain a space, and it keeps bold and italic from fontStyle. Colors with an alpha channel are blended over editor.background.
A slot that the theme doesn't map keeps the built-in color, so parts of fx stay gray. To change one, copy the file and add a colors entry for it, or write a fx theme file instead.
The theme's type can be light, dark, hc, or hc-light, and any other value makes the theme invalid. Without type, fx reads the brightness of editor.background, and treats the theme as dark when that color is missing.
Light and dark variants
fx applies a named theme only when the theme's type matches the terminal's current mode. A dark theme in a light terminal is not adjusted or inverted. If the types differ, fx looks for a sibling file. For a name that ends in -dark, -light, _dark, or _light, fx tries the same name with the opposite ending, so github-dark pairs with github-light. When no sibling matches, fx uses the built-in theme for the terminal's mode.
fx checks again when the terminal switches between light and dark, so a pair of files follows your terminal. A theme set to light or dark doesn't follow it.
Troubleshoot a theme
fx doesn't show an error when it can't use a theme. It falls back to the built-in theme for the terminal's mode. Check these in order:
- The file is
~/.fx/themes/<name>.json, andthemeis<name>without.json. - The file is valid strict JSON, with no comments or trailing commas, and an fx theme file uses
#rgbor#rrggbbfor every color. Check it withjq . ~/.fx/themes/<name>.json. - The file's
typematches your terminal's mode, or a-darkand-lightpair exists. An fx theme file withouttypecounts as dark. - You restarted fx after editing the file.
To see why fx skipped a theme, write the theme trace to a file and read it:
FX_TRACE_LOG=/tmp/fx-theme.log FX_TRACE_SCOPES=theme fxEach line starts with a timestamp and [theme]. At startup, fx writes nothing when it uses the theme as it is. These lines explain a fallback or a switch:
| Trace line | Meaning |
|---|---|
custom_theme_load_failed name=<name> err=ThemeNotFound | No file ~/.fx/themes/<name>.json exists. |
custom_theme_load_failed name=<name> err=InvalidName | The name has a character that fx doesn't allow, or is longer than 64 characters. |
custom_theme_load_failed name=<name> err=InvalidTheme | The file is larger than 1 MiB, isn't valid JSON, or holds a value that fx can't use. |
theme_variant_fallback name=<name> terminal_light=<true or false> | The theme's type doesn't match the terminal's mode, and no sibling file fits. |
theme_variant_swapped from=<name> to=<sibling> | fx switched to the sibling file for the terminal's mode. This isn't a failure. |