Hassle-free Visual Studio Code Theme: Building an Extension | CSS tricks

Hassle-free Visual Studio Code Theme: Building an Extension | CSS tricks

8 minutes, 46 seconds Read

Years ago, when I read Sarah Drasner’s article on creating a VS Code theme, I quietly thought to myself: That’s a lot of work… I’m never going to make a theme…

But lo and behold, I went ahead and made one – and it took less than six hours to get most of the theme working, and then a day or two to polish up my final tweaks.

In this article, I want to walk you through my process of creating this theme, along with the actual steps I took to create it.

I think talking about the process is powerful because I went from Nah, too much work Unpleasant Oh, I can do it. It’s done..? all within a few hours. (The rest is just time spent polishing).

I never wanted to make a VS Code theme…

I was in the middle of redesigning my website. I designed a super duper old design that I’ve wanted to change for years – and I finally started moving.

Two overlapping screenshots of the website. The left is the old design and the right is the new design.

I used Dracula theme for code snippets in my old design and it worked because Dracula was the only thing that brought a pop of color to my otherwise stark design.

But it didn’t work well with my new site design.

Two overlapping screenshots of a web page with code snippets highlighted in the syntax. On the left is the old theme and on the right is the new theme, which is more colorful.

All I wanted to do was improve the syntax highlighting of the code blocks so that they fit in better with the rest of the site.

That was the beginning of it all.

Shiki CSS variable themes made it easy

I use Astro for my website. Shiki is a syntax highlighter built into Astro by default.

After some quick research, I realized that Shiki allows you to create themes with CSS variables – and we only have to choose a handful of colors.

Shows the 11 CSS variables defined for the Shiki theme.

That doesn’t sound too complicated, so I enabled AI to build out a Shiki theme based on the CSS variables. Here are the CSS and JavaScript you’ll need if you’re also using Astro:

:root {
  --shiki-foreground: #eeeeee;
  --shiki-background: #333333;
  --shiki-token-constant: #660000;
  --shiki-token-string: #770000;
  --shiki-token-comment: #880000;
  --shiki-token-keyword: #990000;
  --shiki-token-parameter: #aa0000;
  --shiki-token-function: #bb0000;
  --shiki-token-string-expression: #cc0000;
  --shiki-token-punctuation: #dd0000;
  --shiki-token-link: #ee0000;
}

pre.shiki,
pre.astro-code {
  padding: 1rem;
  border-radius: 0.5rem;
  color: var(--shiki-foreground);
  background-color: var(--shiki-background);
  overflow-x: auto;
}

pre.shiki code,
pre.astro-code code {
  padding: 0;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  background: none;
}
import { createCssVariablesTheme } from 'shiki/core'

const shikiVariableTheme = createCssVariablesTheme({
  name: 'css-variables',
  variablePrefix: '--shiki-',
  fontStyle: true,
})

export default defineConfig ({
  // ...
  markdown: {
    shikiConfig: {
      theme: shikiVariableTheme
    }
  }
})

I did a quick experiment with the colors I had already used for my website and compared them to several popular themes, such as Dracula, Sarah’s Night owlAnd Moonlight 2.

This gave me the confidence to take my own theme one step further, as the syntax highlighting was developing in the right direction.

But to take this further, I had to leave the CSS variable themes behind and dive in TextMate tokens. It was essential because certain code blocks looked absolutely horrible and TextMate tokens provide more granular control over how and what gets color.

This is where the “hard” part begins.

Let AI help with TextMate scopes

Luckily, AI is here to help. If it weren’t for AI, I might have given up at this point.

This is what I need my AI to do:

  1. I said I wanted to create a custom theme.
  2. I told it to create a scaffold for me.
  3. I asked it to find the Moonlight 2 theme files as a reference and create the TextMate scope tokens based on that.

I got it to consolidate the colors used in semantic keywords like foreground, background, keyword — like Shiki’s variable CSS theme.

And I asked him for all the colors in one color object, so I can create a palette object containing only the semantic names.

This is roughly what it created:

const colors = {
  purple: '...',
  blue: '...',
  // ...
}

const palette = {
  foreground: '...',
  background: '...',
  // ...
}

export default {
  colors: {
    // Used for theming the text editor
  },
  displayName: 'Display Name of your Theme',
  name: 'your-theme-name',
  tokenColors: [
    {
      name: 'Scope name (optional)',
      scope: [/*scopes used*/],
      settings: {
        foreground: /* change color */,
        background: /* background of the text */,
        fontStyle: /* normal, bold or italic */,
      }
    }
  ]
}

You need to provide JSON for VS Code to configure things, so I also have AI to create a build script that converts the above format into a .json file.

You can find the build script and everything I used in the GitHub repository.

Debug locally

It was impossible to debug syntax highlighting on my website because I had to manually restart the server every time I changed a variable.

So I asked AI for a suggestion.

It said I can use it VS Code’s extension host for local development, and then went on to create a .vscode/launch.json file with the following contents:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Extension",
      "type": "extensionHost",
      "request": "launch",
      "args": [
        "--extensionDevelopmentPath=${workspaceFolder}"
      ]
    }
  ]
}

To perform this, you can use F5 (Windows) or Fn + F5 (Mac) and a new editor window will appear. In this new window you can change the theme to your own.

Finding a window that uses the extension host is quite easy because:

  • If you change your theme, that window will have a different theme than your other open text editors.
  • The keyword Extension Host is prominently featured in the title.
The following text is displayed: Extension Development host, index.astro, zellwk.com.

Now everything is a blur right now so I can’t remember if you should take in the next thing package.json theme switching file to work in extension host. If so, please state:

{
  "contributes": {
    "themes": [
      {
        "label": "Your Theme Name",
        "uiTheme": "vs-dark",
        "path": ".json"
      }
    ]
  }
}

Understanding the TextMate scopes

At first I copied and pasted images and tried to get AI to match different tokens to the colors I chose. But it quickly became frustrating.

Or:

  • the AI ​​misunderstood the scope of the textmate, or
  • it was overwritten by something else.

I didn’t know. But luckily you can easily debug the TextMate scopes with the “Developer: Inspector Editor Tokens and Scopes” command.

The VS Code control panel opens and highlights a command called Developer: Inspect editor tokens and scopes.

When you are in this mode you can click on any text and a window will pop up. Here you will find all the information you need to adjust the TextMate scopes.

An inspector popover in VS Code with information for the variable color-purple-100.

Here’s how you can read what’s going on:

  • Foreground: Tells you the current active range. In this case it is the active range variable.
  • TextMate ranges: Tells you what are the available TextMate scopes you can use for this specific token.

TextMate scopes work in an interesting way. Through experimentation I discovered the following, so it may not be 100% accurate:

  1. You can use any part of the available scopes. variable, variable.propAnd variable.prop.css all work.
  2. By specifying more properties you can increase specificity. variable.prop.css > variable.prop > variable in terms of specificity.
  3. The higher range is more specific than the lower. variable > meta.function.misc.css.
  4. You can use other scopes with it, such as CSS selectors if you need to overwrite a higher range. meta.function variable > variable

How I chose colors for the theme

This is the most important topic when creating a theme. There is no point in using the theme if syntax highlighting does not support the developer in reading code.

Two articles come to mind here:

Essentially, the principles I took from both articles are:

  • We want highlights to stand out.
  • Colors will look very similar if you use the same lightness and chroma, and it will be difficult to tell them apart.
  • If everything is highlighted, nothing will be highlighted.
  • When everything is important, nothing is.

In short, we’re talking about the contrast principle when designing. Since I’m already drafting it for someone to read, the following thoughts came in:

  1. How do I guide my eyes?
  2. What are important elements I need to see/know?
  3. Which elements are less important?

I started working with this:

  • Functions And methods were important, so they had to be strong, so I used them cyan which is the strongest color in my palette.
  • The export keyword is also important because it means an export!
  • Keywords like import And function can be quite muted, so purple it is.
  • Strings can be green – because they look quite nice in a list of text in a JSON file.
Shows the JSON configuration for a dependencies object with a list of packages used in the project to illustrate the use of syntax highlighting colors.
If the text wasn’t green… this might be hard to look at.

I played around with the rest of the colors a bit, but I ended up with the following:

  • Constants Are orange because it is quite easy to recognize them
  • Variables Are white-ish because that’s most of the text. Adding colors creates the ‘Christmas Lights Diarrhea’ effect that Tonsky mentioned.
  • Properties Are blue because they are like workhorses that need color differentiation, but not enough to attract too much attention.
Show syntax highlighting for JavaScript code.

Then I went to HTML/Astro/Svelte:

  • Tags are red because they are quite important – and red is easier to read than cyan.
  • Attributes Are purple for the same reason as keywords.
  • Components Are orange because they have to be different Tags.
  • Bonus points: Tags And Components are related – so red And orange feels just right here.
Syntax highlighting for Svelte code appears.

And finally CSS syntax highlighting. Almost everything seemed fine at this point, except that:

  • CSS Functions should be cyan so in JS.
  • Punctuation needs to be muted so we can get the -- from the rest of the text.
  • Property can be green because blue is too boring in this context – and green is beautiful for the eyes in contrast with other strong colors.
Show syntax highlighting for CSS code.

It’s a shame that the syntax highlighting for nested classes is a bit messed up (they are greenbut they should be orange), but there’s not much I can do about it.

Show syntax highlighting for CSS code.

Debugging colors

VS Code is built on it Electronso it’s easy to debug and test colors. What I had to do was fire up devtools, inspect the color I wanted to change and change it directly to get a live update!

Packing

The most important thing I learned during this process is to go with the flow. One opening can lead to another, and then to another, and something that seems “impossible” can turn into “Oh, is it done?” within a few hours.

I name my theme Twilight Cosmos (AI helped with the naming). You can find it at:

How did I publish my extension? That’s the subject of a short follow-up article I’m working on.

In the meantime, here’s the GitHub repository if you want to build on what I’ve done. Feel free to suggest edits to improve this theme too!

Finally, sign up for my email newsletter if you are interested in my creation adventures. 🙂

That’s it. Thanks for reading and I hope you enjoyed it!

#Hasslefree #Visual #Studio #Code #Theme #Building #Extension #CSS #tricks

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *