Color.DesignTokens
(Color v0.11.0)
Copy Markdown
Encode and decode W3C Design Tokens Community Group color tokens, per the October 2025 draft of the DTCG Color spec.
Design tokens are a portable JSON format for design-system values. A color token looks like this:
%{
"$type" => "color",
"$value" => %{
"colorSpace" => "oklch",
"components" => [0.63, 0.19, 259.5],
"alpha" => 1.0,
"hex" => "#3b82f6"
}
}This module converts between those maps and the library's
Color.* structs, so palettes can round-trip through any tool
that speaks the DTCG format (Style Dictionary, Figma, Penpot,
and so on).
Encode
iex> {:ok, color} = Color.new("#3b82f6")
iex> token = Color.DesignTokens.encode(color)
iex> token["colorSpace"]
"srgb"To emit in a different colour space, convert first:
iex> {:ok, oklch} = Color.convert("#3b82f6", Color.Oklch)
iex> Color.DesignTokens.encode(oklch) |> Map.get("colorSpace")
"oklch"Or use encode/2 with the :space option — it runs the
conversion for you:
iex> token = Color.DesignTokens.encode("#3b82f6", space: Color.Oklch)
iex> token["colorSpace"]
"oklch"Decode
iex> value = %{"colorSpace" => "oklch", "components" => [0.63, 0.19, 259.5], "alpha" => 1}
iex> {:ok, oklch} = Color.DesignTokens.decode(value)
iex> match?(%Color.Oklch{}, oklch)
trueDecode also accepts full tokens (with $type / $value), and
a hex-only fallback:
iex> {:ok, srgb} = Color.DesignTokens.decode(%{"hex" => "#3b82f6"})
iex> Color.to_hex(srgb)
"#3b82f6"Unknown colour spaces or malformed input return
{:error, %Color.DesignTokensDecodeError{}}.
Supported colour spaces
The DTCG spec and our mapping:
DTCG colorSpace | Struct |
|---|---|
"srgb" | Color.SRGB |
"srgb-linear" | Color.RGB with working_space: :SRGB |
"hsl" | Color.HSL |
"lab" | Color.Lab |
"lch" | Color.LCHab |
"oklab" | Color.Oklab |
"oklch" | Color.Oklch |
"display-p3" | Color.RGB with working_space: :P3 |
"rec2020" | Color.RGB with working_space: :Rec2020 |
"prophoto-rgb" | Color.RGB with working_space: :ProPhoto |
"a98-rgb" | Color.AdobeRGB |
"xyz-d50" | Color.XYZ with illuminant: :D50 |
"xyz-d65" / "xyz" | Color.XYZ with illuminant: :D65 |
Alias tokens
DTCG supports alias tokens — "$value" => "{palette.blue.500}"
— that reference another token. This module does not resolve
aliases. Resolve them in the caller (where you have the full
token tree) before passing values here. decode/1 returns a
specific :alias_not_resolved error if it sees one, so you can
handle them cleanly.
Summary
Functions
@spec decode(map() | binary()) :: {:ok, struct()} | {:error, Exception.t()}
Decodes a DTCG color token (or $value map) into a Color.*
struct.
Arguments
tokenis either a full token (%{"$type" => "color", "$value" => ...}) or a bare$valuemap. Alias strings ("{path.to.token}") are explicitly rejected — see the module doc.
Returns
{:ok, struct}on success.{:error, %Color.DesignTokensDecodeError{}}on failure.
Examples
iex> {:ok, oklch} = Color.DesignTokens.decode(%{"colorSpace" => "oklch", "components" => [0.5, 0.1, 180]})
iex> Float.round(oklch.l, 2)
0.5
iex> {:error, %Color.DesignTokensDecodeError{reason: :unknown_color_space}} =
...> Color.DesignTokens.decode(%{"colorSpace" => "fake-space", "components" => [0, 0, 0]})
Like decode/1 but raises on error.
Examples
iex> Color.DesignTokens.decode!(%{"hex" => "#3b82f6"}) |> Color.to_hex()
"#3b82f6"
@spec encode( Color.input() | struct(), keyword() ) :: map()
Encodes a colour into a DTCG $value map.
Arguments
coloris anything accepted byColor.new/1or already aColor.*struct.
Options
:spaceis the target colour space for the encoded token — any module accepted byColor.convert/2. Defaults to the colour's current space (no conversion).
Returns
- A DTCG
$valuemap with"colorSpace","components", optional"alpha", and"hex"fallback.
Examples
iex> token = Color.DesignTokens.encode("#3b82f6")
iex> token["colorSpace"]
"srgb"
iex> token = Color.DesignTokens.encode("#3b82f6", space: Color.Oklch)
iex> token["colorSpace"]
"oklch"
@spec encode_token( Color.input() | struct(), keyword() ) :: map()
Encodes a colour and wraps it as a full DTCG color token
(%{"$type" => "color", "$value" => ...}).
Arguments
coloris anything accepted byColor.new/1.
Options
See encode/2.
Returns
- A DTCG token map with
$typeand$value.
Examples
iex> token = Color.DesignTokens.encode_token("#3b82f6")
iex> token["$type"]
"color"
iex> token["$value"]["colorSpace"]
"srgb"