Looking for a Front-End Developer and Design Systems Practitioner?

I currently have some availabilty. Let's talk!.

Always Twisted

Design Tokens have landed in Penpot, kinda

On This Page:

At the end of last week I found myself spending the day at my partners antiques centre whilst they were away. It was quiet, not so many PPPs (pick up, put down, p*ss off) but a few SSSs (small significant sales).

I found myself sat on an old upholstered chair with my laptop and thought I’d have a go at creating a ‘design tokens starter’ for Penpot.

After working out how to create circles and text, group them, duplicate them and group them again I was already tired at how much work was involved (“this would be easier in code” I said to my-(front-end-developer)-self).

I then spotted it, the Design Tokens panel and shifted gears.

the design tokens panel UI for Penpot

Nice, a way to create design tokens built into the UI, including themes, sets and the tokens themselves.

I clicked the little plus icon next to border-radius and was given a popup to add a new token.

the design tokens panel UI for Penpot with a popup next to is with form fields for a new token - name, value, description

Adding a new theme also had a similar pop up:

a 'add new layer' popup with fields for group and theme

Adding a new set gave me something a little different:

the design tokens panel UI with a form input for a new set name

At the bottom of this side panel had another button that was labelled ‘tools’. I clicked it, who doesn’t click a new button.

a popup containing two items - import and export above a button titled 'tools'

Ooh, an “import” and an “export” option. “Ok, let’s look for some documentation on this.” I thought and went to my favourite browser of choice and started searcing.

To The Documentation!

I found documentation explaining this panel (and a bit more) on their site.

It’s using the W3C Design Tokens Community Group Draft Format, it shows how you can reference tokens, what tokens you can create, edit, and use. It also introduces “Token Sets” (layers, or teirs pehaps) and “Token Themes”.

Tokens

Creating a token using the UI allows you to add:

The available tokens (so far) are:

(sadly, at the time of writing this, anything for typography seems to be missing. This new Design Tokens implementation is brand new so I hope we will see something coming soon). As this implementation is making use of the specification you can also reference other tokens:

the new token popup that shows how it is possible to reference an existing token in a new token

Token Sets

This option gives you the ability to have defined layers (teirs) of your Design Tokens. So you can group related tokens into an easy ‘turn off and on-able’ set. You can also group token sets into a visual ‘folder’ in the UI:

a sort of folder strucutre of token sets with global and modes, modes has light and dark nested

Token Themes

Themes allow you to group your token sets for a specific context, like a unique brand or theme. Again you can also group your themes like you can with token sets. You can also apply the same token sets to multiple themes - which would be great for a multi-brand system that has similar base layer tokens. You can define all of this in the edit theme popup:

the themes popup showing what active sets are selected

Creating a quick example

I quickly popped in some tokens, added some themes and sets and came to a UI panel like this:

an example of the Penpot UI for Design Tokens showing a theme selected, the token sets that are active and some groups of design tokens underneath

We have ‘brand-a’ as the active theme, we have the global and both mode token sets active and we seeing the tokens that are part of the global set at the bottom of the UI.

But, as a developer…

This all looked pretty cool, as a front-end developer I wanted to know more about the importing and exporting of data. As I’d already created a few tokens in the app, the best way to see how you can import a .json file was to export what I had.

Code languagejson
{
"global": {
"red": {
"400": {
"$value": "#f44336",
"$type": "color",
"$description": ""
},
"500": {
"$value": "#ffcdd2",
"$type": "color",
"$description": ""
}
},
"radius": {
"100": {
"$value": "2px",
"$type": "borderRadius",
"$description": "2px border rarius"
},
"200": {
"$value": "4px",
"$type": "borderRadius",
"$description": "4px border rarius"
},
"300": {
"$value": "8px",
"$type": "borderRadius",
"$description": "8px border rarius"
},
"400": {
"$value": "16px",
"$type": "borderRadius",
"$description": "16px border rarius"
}
},
"blue": {
"400": {
"$value": "#2196f3",
"$type": "color",
"$description": ""
},
"900": {
"$value": "#0d47a1",
"$type": "color",
"$description": ""
}
}
},
"mode/light": {
"color": {
"background": {
"$value": "#000000",
"$type": "color",
"$description": ""
}
}
},
"mode/dark": {
"color": {
"background": {
"$value": "#FFFFFF",
"$type": "color",
"$description": ""
}
}
},
"$themes": [
{
"name": "brand-a",
"group": "",
"description": "",
"is-source": false,
"id": "61d2de80-46cc-80e4-8006-030e7ccd5f46",
"modified-at": "2025-04-10T11:39:46.156+01:00",
"selectedTokenSets": {
"mode/light": "enabled",
"mode/dark": "enabled",
"global": "enabled"
}
},
{
"name": "brand-b",
"group": "",
"description": "",
"is-source": false,
"id": "61d2de80-46cc-80e4-8006-031314d7f8c6",
"modified-at": "2025-04-10T11:39:52.621+01:00",
"selectedTokenSets": {
"mode/light": "enabled",
"mode/dark": "enabled",
"global": "enabled"
}
}
],
"$metadata": {
"tokenSetOrder": [
"global",
"mode/light",
"mode/dark"
],
"activeThemes": [
"/brand-a"
],
"activeSets": [
"mode/light",
"mode/dark",
"global"
]
}
}

So we get the code interpretation of the tokens I added, following the DTCGs specification using $value, $type, and $description and we also get some other information.

Code languagejson
"$themes": [
{
"name": "brand-a",
"group": "",
"description": "",
"is-source": false,
"id": "61d2de80-46cc-80e4-8006-030e7ccd5f46",
"modified-at": "2025-04-10T11:39:46.156+01:00",
"selectedTokenSets": {
"mode/light": "enabled",
"mode/dark": "enabled",
"global": "enabled"
}
},
{
"name": "brand-b",
"group": "",
"description": "",
"is-source": false,
"id": "61d2de80-46cc-80e4-8006-031314d7f8c6",
"modified-at": "2025-04-10T11:39:52.621+01:00",
"selectedTokenSets": {
"mode/light": "enabled",
"mode/dark": "enabled",
"global": "enabled"
}
}
],
"$metadata": {
"tokenSetOrder": [
"global",
"mode/light",
"mode/dark"
],
"activeThemes": [
"/brand-a"
],
"activeSets": [
"mode/light",
"mode/dark",
"global"
]
}

The themes seem to have some propietary .json for the application, but it shows us:

Below the themes we also get some more propietary .json. This $metadata looks like it helps the Penpot UI turn on (or off) whatever token theme and it’s token sets are active.

A Quick Wrap Up, Before Part Two

Penpot’s Design Tokens implementation marks a promising but (at the moment) incomplete step forward. While the tool now supports W3C DTCG-compliant tokens – enabling themes, token sets, and cross-referencing – gaps remain.

The absence of typography tokens (font families, weights, line heights) undermines its utility for holistic design systems (but this feature is a week old, let’s give it some time).

Creating tokens manually in the UI also feels laborious (to me) compared to code-driven workflows, and proprietary metadata fields like ⁠$themes can risk vendor lock-in.

In “Part Two”, I will look at using Style Dictionary to generate a format that Penpot can use and (hopefully) see how we could use Penpots exported .json as a source of truth too (if needed).

I’m still in two minds at where I see Design Tokens (as a thing) being stored as a source of truth. The pendulum swings from code or design to it’s own place that design and code tools should import (but I guess that might be a article in itself).

An update

A day or two after publishing this, Xaviju reached out to update me on some of the points that I mentioend in the wrap up.

  1. They are "already working on composite tokens and typography is a top priority"
  2. "A code editor is on our roadmap" 👀
  3. They "are working to improve the current DTCG standard with themes" so the metadata could be improved to " provide a better experience"

I also noticed that, with Laura, Penpot have released a short video on using Design Tokens with Penpot.

Wondering how to output tokens into different formats for different platforms?

I can configure tools to output tokens into the formats your teams need.

get in touch!