New CSS features can sometimes make it easier and more efficient to code designs we already knew how to create. This efficiency could stem from reduced code or hacks, or improved readability due to the new features.
In that spirit, let’s revamp what’s under the hood of a bar chart.
The chart metric is based on percentage, as in “some number out of 100.” Let’s say we’re working with a grid containing 100 rows. That ought to stress test it, right?
Next, we add the bars to the grid with the grid-column and grid-row properties:
Right off the bat, I want to note a couple of things. First is that sibling-index() function. It’s brand new and has incomplete browser support as of this writing (come on, Firefox!), though it’s currently supported in the latest Chrome and Safari (but not on iOS apparently). Second is that attr() function. We’ve had it for a while, but it was recently upgraded and now accepts data-attributes. So when we have one of those in our markup — like data-value="32" — that’s something the function can read.
With those in place, that’s really all we need to create a pretty darn nice bar chart in vanilla CSS! The following demo has fallbacks in place so that you can still see the final result in case your browser hasn’t adopted those new features:
Yes, that was easy to do, but it’s best to know exactly why it works. So, let’s break that down.
Automatically Establishing Grid Columns
Declaring the sibling-index() function on the grid-column property explicitly places the list items in consecutive columns. I say “explicit” because we’re telling the grid exactly where to place each item by its data-value attribute in the markup. It goes first <li> in first column, second <li> in second column, and so forth.
That’s the power of sibling-index() — the grid intelligently generates the order for us without having to do it manually through CSS variables.
/* First bar: sibling-index() = 1 */
grid-column: sibling-index();
/* ...results in: */
grid-column: 1;
grid-column-start: 1; grid-column-end: auto;
/* Second bar: sibling-index() = 2 */
grid-column: sibling-index();
/* ...results in: */
grid-column: 2;
grid-column-start: 2; grid-column-end: auto;
/* etc. */
Automatically Establishing Grid Rows
It’s pretty much the same thing! But in this case, each bar occupies a certain number of rows based on the percentage it represents. The grid gets those values from the data-value attribute in the markup, effectively telling the grid how tall each bar in the chart should be.
/* First bar: data-value="32" */
grid-row: span attr(data-value number);
/* ...results in: */
grid-row: span 32
/* Second bar: data-value="46" */
grid-row: span attr(data-value number);
/* ...results in: */
grid-row: span 46
The attr() function, when provided with a data type parameter (the parameter value number in our case), casts the value retrieved byattr()into that specific type. In our example, the attr() function returns the value of data-value as a <number> type, which is then used to determine the number of rows to span for each bar.
Let’s Make Different Charts!
Since we have the nuts and bolts down on this approach, I figured I’d push things a bit and demonstrate how we can apply the same techniques for all kinds of CSS-only charts.
For example, we can use grid-row values to adjust the vertical direction of the bars:
Or we can skip bars altogether and use markers instead:
We can also swap the columns and rows for horizontal bar charts:
Wrapping up
Pretty exciting, right? Just look at all the ways we used to pull this stuff off before the days of sibling-index() and an upgraded attr():
You’d think that publishing a VS Code extension is an easy process, but it’s not. (Maybe I’m used to the ease of publishing npm packages and take registries for granted.)
Anyway, you have to publish your theme in two places:
You might also want to publish to npm for others to use your theme easily for other contexts — like syntax highlighting via Shiki.
Preparing your theme
When you name your theme, you cannot put it under a scope like @scope/theme-name. Doing so will prevent you from publishing to Open VSX.
So, make sure your theme name is unscoped. (The theme word is optional):
{
"name": "twilight-cosmos-theme",
}
To include an icon for your theme, you need a 128px square image file that can be accessible within your project. Put this under the icon property to point to the file:
{
"icon": "path/to/icon.png",
}
Next, you want to ensure that you have a contributes key in your package.json file. VS Code and other text editors search for this to find themes.
Microsoft lets you publish to Visual Studio Marketplace via vsce if you have a personal access token from an Azure DevOps account.
Unfortunately, while creating this article, I encountered several problems setting up my Azure Devops account so I had to publish my extension via the manual route.
I’ll talk about both routes here.
Before publishing, you need to have a Visual Studio Marketplace account. So, sign up for one if you don’t have it yet.
Then do the following:
Click on Publish Extension.
Create a publisher account.
This step is needed for publishing both via vsce and the manual route.
Publishing via VSCE
For this to work, you need a Azure DevOps account. When you have that, you can create a Personal Access Token with these steps.
Note: It’s kinda irritating that you can’t have an lifetime access token with Azure DevOps. The maximum expiry is about one year later.
Also note: I had immense trouble creating my Azure DevOps account when I tried this — the back end kept hanging and I couldn’t find the right page, even when I copy-pasted the URL! Anyway, don’t be alarmed if this happens to you. You might just need to wait 1-2 days before you try again. It will work, eventually.
Once you have the personal access token, the rest of the steps is pretty straightforward.
First, you login to VSCE with your publisher ID that you created in Visual Studio Marketplace. (Insert the publisher ID, not the user ID!).
npx vsce login <publisher_id>
You’ll have to insert the access token when it asks you to. Then, run the next command to publish to the marketplace:
npx vsce publish
And you’re done!
Publishing manually
You’ll have to follow this route if you had problems with the personal access token like I did. Thankfully, it’s pretty straightforward as well. You can go to Visual Studio Marketplace and do the following:
Click on Publish Extensions.
Click New Extension.
Use the vsce package command to package your extension as a visx file.
Drag and drop the packaged visx file to upload your extension.
That’s it!
Getting verified on Visual Studio Code
If this is your first extension, you can only get “verified” on the Visual Studio Marketplace if your extension is at least six months old. So, if you want to get verified, set a reminder in six months and visit this page for more information.
Publishing to Open VSX
Thanks to Claude, I understood VS Code uses the Visual Studio Marketplace, but other text editors, like Cursor, use Open VSX.
Publishing to Open VSX is a bit more complex. You have to:
Then, finally, run npx ovsx publish to publish your package.
Likewise, ovsx will ask you for a personal access token when you try to publish for the first time. Thankfully, ovsx seems to have a lifetime access token seems so we don’t have to worry about it expiring.
Claiming the publisher namespace
This is essentially getting “verified” with Open VSX, but Open VSX calls it “claiming” the publisher namespace to get verified. Without harping on the language too much — this process takes a bit of to-and-fro but can be done now (instead of six months later).
Once you have created a publisher namespace, you’ll see a glaring warning sign:
Include your GitHub repository (if you make it publicly available).
Offer to give access temporarily to your GitHub repository (if it’s private).
And someone will handle the rest.
The team at Eclipse Foundation seems to be pretty responsive, so I wouldn’t worry about communication breakdown here.
Including images for your theme
It makes sense to include images to showcase your theme in the Readme.md file. Doing so allows users to get a sense of your theme colors before deciding whether they want to download it.
Unfortunately, both VS Marketplace and Open VSX do not allow you to use relative URLs — images will be broken if you use relative links from your repository — so you have to link to an absolute URL instead.
The best place to link to is the GitHub repository, as long as it is set to public access.