<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Always Twisted| Articles</title>
  <subtitle>A feed of the latest articless from our blog.</subtitle>
  <link href="https://www.alwaystwisted.com/feed.xml" rel="self"/>
  <link href="https://www.alwaystwisted.com/"/>
  <updated>2026-08-04T00:00:00Z</updated>
  <id>https://www.alwaystwisted.com</id>
  <author>
    <name>Stu Robson</name>
    <email>hi@sturobson.com</email>
  </author>
  
    
    <entry>
      <title>Introducing Linting to your Existing Design Tokens System</title>
      <link href="https://www.alwaystwisted.com/articles/introducing-linting-to-an-existing-token-system.html"/>
      <updated>2026-08-04T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/introducing-linting-to-an-existing-token-system.html</id>
      <content type="html">
        <![CDATA[
        <p>Adding testing and linting to an established design token system can sound
straightforward until that first run returns pages and pages of warnings and errors.
Teams will often swing between the pendulum of two extremes. Block everything and slow delivery to
an absolute crawl, or keep everything as warnings and never improve quality.</p>
<p>Sometimes they'l decide to skip linting altogether because the debt is simply
too ugly to look at before the first coffee of the day.</p>
<p>There can be a better path. Start with visibility, then introduce a few guardrails,
then raise the standards over time ... at least that's a theory.</p>
<p>Whether it works depends less on the process and more on who has to do the work.</p>
<h2 id="why-rollouts-fail" tabindex="-1">Why Rollouts Fail</h2>
<p>Most token linting rollouts fail for process reasons, not technical ones.</p>
<p>A common pattern looks something like this: the team turns on &quot;strict mode&quot;
immediately, the existing debt blocks any and every change, and contributors
start bypassing the checks the moment they're under pressure to ship. Confidence
drops, and the whole idea of linting gets quietly ignored - like an &quot;Invasion of
the Body Snatchers&quot; situation, it creeps in without anyone announcing it, and
by the time you notice, half the team has already given up on it.</p>
<p>The issue isn't that the linting is wrong. It's the sequencing.</p>
<h2 id="a-practical-rollout-plan" tabindex="-1">A Practical Rollout Plan</h2>
<p>Use a phased approach - observe first, block critical failures second, then expand
rules gradually. This isn't universal. Teams with greenfield tokens or strict
change control don't need to move this slowly. But if you've got years of tokens,
multiple owners, and shipping pressure, this sequence tends to work better than
jumping straight to enforcement.</p>
<h3 id="phase-1-%E2%80%94-run-the-baseline-audit" tabindex="-1">Phase 1 — Run The Baseline Audit</h3>
<p>Run linting in &quot;report only&quot; mode against the full set of Design Tokens. Do not block commits
or merges yet. You don't even need to announce to everyone that you've started it. Just run it and look at the results.</p>
<p>Your goal is to clarify and classify what you have. Structural failures like broken
references, circular dependencies, and invalid types sit in one bucket. Quality
issues such as naming inconsistency, duplicate values, or weak descriptions sit
in another. Accessibility risks - contrast failures, missing mode pairings - are
a third.</p>
<p>This gives you an idea of the technical risk and cleanup effort before you enforce
anything. You'll probably find more than you expectm, but hopefully not too much.</p>
<p>This will take some time, maybe a couple of hours to a full day for a small
system, perhasp a week for systems with hundreds of Design Tokens across multiple files.
The actual audit is the quick bit, going through and processing the results,
working out priorities to take will take longer (a lot longer) than running the
linting tools.</p>
<h3 id="phase-2-%E2%80%94-fix-the-critical-errors" tabindex="-1">Phase 2 — Fix The Critical Errors</h3>
<p>Now prioritise the issues that would actually break the Design Token
transformation or the code that gets shipped: broken references pointing to
tokens that no longer exist, circular dependencies where tokens reference one
another in a loop, type-value mismatches, and missing required structure where
a token doesn't have the shape the system expects.</p>
<p>Do not move to any sort of &quot;blocking mode&quot; until these are under control. This is the point at
which most linting rollouts stall.</p>
<p>The debt is real, the cleanup will take time, and meanwhile new Design Tokens
keep getting added that should be linted. Some teams get stuck here for months
because they try to fix everything at once instead of blocking new problems
while cleaning up old ones. That's a losing battle.</p>
<p>If legacy critical errors remain when you try to enforce rules, every commit
becomes a negotiation. Developers will either bypass checks or get blocked
constantly, and linting starts getting quietly ignored.</p>
<p>How long this takes will vary wildly. A small team with a small suite of
Design Tokens can work through this a lot quicker than a team that has been
shipping Design Tokens for several years with multiple owners. The hidden risk is
that cleanup work will compete with feature work, and I'm sure we can guess
which one wins. Dedicate time explicitly, or Phase 2 never ends.</p>
<h3 id="phase-3-%E2%80%94-turn-on-blocking-for-critical-rules" tabindex="-1">Phase 3 — Turn On Blocking for Critical Rules</h3>
<p>Once the chosen critical categories are cleaned up, enforce the rules in pre-commit and CI.</p>
<p>Pre-commit is best used for fast, critical checks only. The CI pipeline should
run full validation and surface warnings without blocking everything. The
release gate is where you enforce &quot;strict mode&quot; for published outputs.</p>
<p>This gives contributors quick, local feedback while keeping CI as a mandatory
backstop.</p>
<p>Turning the checks on won't take long, but expect a noisy few days (maybe a
week or two) as people hit rules they didn't know existed - which might say more
about your documentation than your linter. Some will blame the tool instead of
the tokens.</p>
<h3 id="phase-4-%E2%80%94-manage-any-warnings-as-backlog" tabindex="-1">Phase 4 — Manage Any Warnings as Backlog</h3>
<p>Treat non-critical findings as scheduled improvement work: naming cleanup, duplicate
token consolidation, and accessibility improvements are all long-term wins rather
than emergencies.</p>
<p>Batch changes by category instead of trying to clear all warnings in one pass.</p>
<p>This phase is an ongoing endevour. Pick one set of warnings in a sprint and
work through them all. Try to clear everything everywhere all at once and you
just won't - the warnings turn into something in the terminal that everyone
learns to scroll past.</p>
<h3 id="phase-5-%E2%80%94-expand-rules-one-at-a-time" tabindex="-1">Phase 5 — Expand Rules One at a Time</h3>
<p>Only add rules that solve repeated problems your team actually sees in the
Design Tokens. Announce the intent and timeline first, run the new rule in
warning-only mode for a short period so people can adjust, then promote it to
blocking once the team has had time to catch up.</p>
<p>A predictable rollout beats a surprise every time.</p>
<p>Add one new rule at a time - per sprint, or every couple of weeks, whatever
cadence suits your team. Add several at once and you lose visibility into
which one is actually causing the friction.</p>
<h2 id="when-things-get-stuck" tabindex="-1">When Things Get Stuck</h2>
<p>If Phase 2 doesn't finish in a reasonable time, or Phase 3 ends up blocking
everything, you'll need a recovery strategy. Otherwise the team, contributores,
and stakeholders will bypass the linter or abandon it quietly (or pr
not-so-quietly).</p>
<p>Say Phase 2 is stalling - you've been fixing critical errors for two months and
still have 30% of the problems left. Two options here. Pick a cutoff date: after
that date, new tokens follow the rules strictly, and old tokens get an automatic
exception for 90 days with a &quot;revisit&quot; marker. This stops the debt from growing
while you clean up the past. Alternatively, move a chunk of the cleanup into
Phase 4 as warning-level work instead of blockers. Not everything needs to be
critical. If it doesn't break the transformation, it can wait.</p>
<p>If Phase 3 is blocking too many commits - the rules are technically correct but
they're stopping every PR - it usually means the critical rules were too
aggressive, or Phase 2 wasn't actually finished. Don't blame the linter. Revert
the overly strict rules to warning-only, spend more time fixing the underlying
issues, then re-enable. Letting developers bypass the checks to push through it
is how you destroy trust in the whole system.</p>
<p>If you promoted a warning to blocking and it's caused chaos, give it a week. If
adoption is worse than before the change, roll it back to warning-only, fix the
underlying problems properly, then try again. Teams need to believe linting
changes are considered, not punitive or arbitrary.</p>
<p>Adding a temporary exception isn't failure. Abandoning linting is.</p>
<h2 id="ownership-and-communication" tabindex="-1">Ownership and Communication</h2>
<p>Tooling alone will not keep standards high. People need clear ownership, and
showing that clarity is harder than it sounds.</p>
<p>Design Token ownership is usually blurry. A designer adds a colour in Figma.
A developer syncs it to the repo and changes the name. A component team uses it
and documents it differently in their own token file. The token ends up existing
in three forms across three systems, and nobody knows which one is the &quot;source
of truth.&quot; When linting fails, nobody fixes it because nobody knows whose job
that is.</p>
<p>So define it properly. Lint rule configuration shouldn't belong to &quot;the design
system team&quot; in the abstract - it needs a specific person or rotation who
decides which rules matter and when they change. Exception approval shouldn't be
open to anyone either; track who approved what, when, and why, and review it
regularly. It should create a little friction, enough that people try to solve
the underlying problem first, but not so much it's unusable. And someone needs
to own the docs and examples - a decision log covering what you lint, why, how
to fix it, and what doesn't apply to a given team, updated as rules change.</p>
<p>Then make failures actionable. &quot;Circular reference detected&quot; isn't useful on its
own. &quot;color.primary references color.secondary which references color.primary:
fix by changing line 42 to reference color.base.blue instead&quot; is. If a pull
request touches 300 tokens and every violation gets dumped into the output,
nobody reads it - surface new violations first, then warnings, then the existing
backlog. And any exception paths should be documented, rare, and time-locked.
Never approve one without recording why and setting a review date. Untracked
exceptions become permanent drift.</p>
<h2 id="exception-handling-without-chaos" tabindex="-1">Exception Handling Without Chaos</h2>
<p>Some exceptions are legitimate. Most teams have a few. The trouble is knowing
which ones you actually have, and why they exist.</p>
<p>Common cases in design token systems:</p>
<ul>
<li>Vendor tokens that can't be renamed. You sync a third-party design system
and their Design Tokens use <code>snake_case</code> while your convention is <code>kebab-case</code>. You
can't change the vendor's output, so those tokens get an exception.</li>
<li>Legacy platform constraints. Swift restricts which Unicode categories are
valid in variable names. Tokens that were named before that constraint was
understood, or before the system targeted Swift at all, may not conform.
Renaming them touches generated code across multiple platforms. They get an
exception until there's a dedicated migration window.</li>
<li>Transitional naming during migrations. You're moving from a 2-tier token
structure to a 3-tier structure. For six months both exist in the codebase.
The old ones generate linting warnings but removing them would break live
products, so they get a temporary exception.</li>
<li>Third-party component tokens. A team from another part of the org has
contributed tokens for their component library. They follow a naming
convention you don't use, and aligning them would require coordinated changes
across codebases you don't own. The exception lives here until ownership is
clarified or a migration is agreed.</li>
</ul>
<p>For each exception, record why it's allowed, and be specific: &quot;Swift identifier
restrictions&quot; or &quot;vendor output we cannot modify&quot; or &quot;coordination required with
Squad Dave&quot; all tell you something useful later. Record the scope too - &quot;the
token file&quot; isn't good enough, but &quot;all tokens matching <code>@tokens/vendor/**</code>&quot; is.
Record who approved it, because that person owns defending it. And record when
it should be reviewed or removed: a date or a condition, like &quot;Q4 2026&quot; or &quot;when
we ship v3 of the component library&quot; or &quot;no longer needed as of Framework 5.8.&quot;</p>
<p>Untracked exceptions become permanent. A year on, nobody remembers why they
exist, everyone assumes they're intentional, and they end up staying in the
codebase indefinitely.</p>
<h2 id="measuring-success" tabindex="-1">Measuring Success</h2>
<p>You don't need perfect compliance on day one. You need a system that stops
quality from getting worse while the baseline steadily improves.</p>
<p>Healthy signals: critical failures are rare and get fixed quickly, contributors
trust the lint output, rule changes feel predictable, and release consumers stop
seeing avoidable token breakages.</p>
<p>But &quot;healthy signals&quot; is pretty vague, so track something concrete. Time to fix
a linting error in code review is a good one - early on it should be fast,
developers see the error, understand the fix, and push a correction within the
hour. If review stalls because the error is confusing, your messages need work.
If it takes days to get clarification, ownership isn't clear enough.</p>
<p>Watch critical errors in CI too. After Phase 3 this should be close to zero each
week. Seeing five a week two months in tells you Phase 2 wasn't actually
finished.</p>
<p>New exceptions requested per month is worth tracking as well. Expect a spike
early on as teams ask for legitimate carve-outs, then a decline. If exceptions
keep climbing instead, your rules are probably too strict, or don't match how
your teams are actually structured.</p>
<p>Production incidents caused by token problems should drop noticeably once
linting lands. If they don't, either the linting isn't comprehensive enough or
token problems were never your real bottleneck.</p>
<p>Time spent on token-related code review is the last one - it should fall after
Phase 3 because the linter is catching the obvious stuff before a human looks at
it. If review time stays flat, either the linter isn't doing useful work, or
people have started ignoring it.</p>
<p>Pick one or two of these that matter to your team and track them monthly.
That's the real goal - reliable token quality without blocking delivery. You'll
know it's working when the numbers move, not when the process looks tidy on
paper.</p>
<h2 id="start-small%2C-enforce-smart" tabindex="-1">Start Small, Enforce Smart</h2>
<p>If you're introducing linting today, start with one rule that catches a
&quot;high impact&quot; failure. Prove the value quickly by fixing the real faults, then expand
in controlled steps.</p>
<p>A gradual rollout isn't a compromise. It's how linting actually sticks, or at
least how it's most likely to. The difference between success and failure
usually has nothing to do with the tooling and everything to do with timing,
team buy-in, and how much debt you're sitting on.</p>
<p>What actually works is paying attention to your team, your constraints, your
needs, and your debt.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Running and Evolving Your Design Systems Workflow - Metrics, Mistakes, and Scaling</title>
      <link href="https://www.alwaystwisted.com/articles/running-and-evolving-your-design-systems-workflow-metrics-mistakes-and-scaling.html"/>
      <updated>2026-07-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/running-and-evolving-your-design-systems-workflow-metrics-mistakes-and-scaling.html</id>
      <content type="html">
        <![CDATA[
        <p>It's 12 o' clock (and it's a wonderful day). Lars from the mobile team just
noticed something. Their progress bars don't match the ones in the web app. They
dig in. Turns out their team built their own version three months ago because the
original component was taking too long to ship. Nobody told them it was coming.
By the time it shipped, they'd already invested in their own solution.</p>
<p>This is what happens when the workflows start to break. Proposals stack up. Decisions stretch from a week to two. Someone builds around the system because it's faster. The ritual that kept everyone aligned becomes busywork nobody attends. Before you know it, your design system has fractured into separate efforts that don't talk to each other.</p>
<p>The frustrating part is that it's not a failure of design or tooling. The
components work. The tools work. The problem is, the process.</p>
<p>When workflows aren't healthy, even good Design Systems fall apart.</p>
<p>The good news is that workflows are observable and, more importantly, updateable. You can see where they're breaking before they break and fix them before any
damage spreads.</p>
<h2 id="seeing-the-system-clearly" tabindex="-1">Seeing the System Clearly</h2>
<p>Measuring workflow health is different from measuring system adoption or
component usage. You're not tracking how successful the system is. You're
tracking whether the processes and work that run the system are actually working.</p>
<p>Pick a few metrics from project management and adapt them for your Design
Systems workflow health. They won't be perfect. They're meant to show direction,
not precision.</p>
<h3 id="time-to-contribution" tabindex="-1">Time-to-Contribution</h3>
<p>How long does it take to go from idea to live? If simple things take 6 weeks, your process is too cumbersome and people start building their own. If complex work ships in 2 weeks, you might be skipping important
steps like testing or documentation.</p>
<h3 id="contribution-volume" tabindex="-1">Contribution Volume</h3>
<p>How many different people shipped work this month? If it's only the core team, you have a bottleneck. If the number grows, it means people feel safe enough to propose. If it's flat or dropping, something's deterring them. This metric tells you how much psychological safety your process creates.</p>
<h3 id="team-satisfaction" tabindex="-1">Team Satisfaction</h3>
<p>A regularly timed, consistent check-in. Ask directly - &quot;How clear is the
contribution process?&quot; on a 1-5 scale (aim for 4+). Also ask the harder
questions, &quot;How much time do you spend navigating process versus actually
building?&quot;</p>
<h3 id="documentation-completeness" tabindex="-1">Documentation Completeness</h3>
<p>Should hover around 90%. Below 80% and you've stopped enforcing it—components ship half-done. Above 95% and you might be over-documenting. Update monthly.</p>
<h3 id="decision-making-speed" tabindex="-1">Decision Making Speed</h3>
<p>This matters more than most teams realise. If initial feedback takes more than 3
days, people start wondering if anyone's paying attention. If final decisions
drag beyond 2 weeks, people will lose faith in the process.</p>
<h3 id="system-adoption" tabindex="-1">System Adoption</h3>
<p>How many products use your components instead of building their own? No universal target—watch the percentage grow quarter-to-quarter. If it's stuck, the system isn't solving real problems for people who need it.</p>
<p>Track this monthly alongside the others. What matters is movement.</p>
<h2 id="how-workflows-break---common-failures" tabindex="-1">How Workflows Break - Common Failures</h2>
<p>These aren't dramatic failures. They're quiet ones. They happen because they're natural failure modes of communication and structure. I've seen them sink workflows in nearly every design system. The difference between systems that last and systems that collapse usually comes down to catching these patterns early.</p>
<h3 id="one-person-holds-all-the-keys" tabindex="-1">One Person Holds All the Keys</h3>
<p>One person becomes the obvious decision-maker. They care deeply about consistency. They understand the system philosophy better than anyone. Then they go on vacation and everything stops. Proposals sit. Nobody else knows how to decide. It's a single point of failure disguised as good stewardship.</p>
<p>This happens because letting one person decide feels safer than distributing it. But it's fragile.</p>
<h3 id="ownership-becomes-invisible" tabindex="-1">Ownership Becomes Invisible</h3>
<p>A designer builds a button variant. It ships. Six months later, the team notices it breaks at a certain screen size. They try to find who owns it. Nobody knows. Nobody was tracking it. Problems don't get fixed. Knowledge walks out the door when people leave.</p>
<h3 id="documentation-becomes-an-afterthought" tabindex="-1">Documentation Becomes an Afterthought</h3>
<p>Components ship without documentation because shipping feels urgent. It's promised for &quot;next sprint.&quot; It never comes. Code becomes the only documentation. Almost nobody can use the components. Teams build their own instead.</p>
<h3 id="the-same-component-has-different-names-everywhere" tabindex="-1">The Same Component Has Different Names Everywhere</h3>
<p><code>progress-bar</code> in Figma. <code>ProgressBar</code> in the code. &quot;Progress Indicator&quot; in the docs. Someone searching for &quot;indicator&quot; doesn't find it and builds their own. Small inconsistencies compound across hundreds of components.</p>
<h3 id="handing-off-without-talking" tabindex="-1">Handing Off Without Talking</h3>
<p>Designers hand designs to engineers with a file and an emoji. Engineers discover constraints mid-development and loop back. Rework stacks up.</p>
<p>Structure handoffs: thirty-minute meeting with design walkthrough (variants, states, interactions), technical discussion (props, tokens, events, edge cases), scope agreement. Document it. One conversation prevents a week of rework.</p>
<p>Alternative: skip discrete handoff moments. Use a hot potato process instead—designers and engineers work in parallel, swapping context daily or twice weekly so neither group builds in isolation. Faster iteration, fewer surprises. Requires strong co-location and communication norms; distributed teams need rock-solid async documentation to pull it off.</p>
<h3 id="planning-the-perfect-process-that-never-ships" tabindex="-1">Planning the Perfect Process That Never Ships</h3>
<p>You design the perfect process before you start. You plan, and nothing ships. Perfect processes exist only in theory. By the time you finish designing them, circumstances have shifted. Better to document your actual process and iterate. Each iteration is real because it's based on actual experience. Imperfect beats non-existent.</p>
<h3 id="the-process-becomes-heavier-than-the-work" tabindex="-1">The Process Becomes Heavier Than the Work</h3>
<p>A simple button change requires five meetings. Three documents. Four different sign-offs. The process is now slowing everything down. You added requirements to prevent problems that happened once. Nothing is optional anymore.</p>
<p>Tier your requirements by scope. Simple changes don't need full review. Complex work needs extended RFC, multiple reviews, careful rollout. Make it explicit so people know when they can move fast.</p>
<h2 id="as-your-team-grows" tabindex="-1">As Your Team Grows</h2>
<p>Your workflow needs to evolve when the informal approach stops working. The
signal isn't some magic headcount, it's friction. The first time two teams
independently build the same component, you need explicit naming. When proposals
start piling up, you need structured RFC reviews. When people lose track of who
owns what, you need documentation.</p>
<p>When you're small, everyone talks to everyone (hopefully). Write down your decision framework. Start a simple RFC process.</p>
<p>As you grow, information stops propagating organically. You need something like a Design System Council, proper RFC templates, decision logs. Documentation becomes mandatory.</p>
<p>When you're bigger, you probably need real governance. Decisions can get &quot;tiered&quot;. RFC templates get detailed.</p>
<p>The harder part is knowing what to remove. Teams layer structure without removing anything. When you add something, ask what it replaces. A workflow carrying old processes from when you were smaller will feel heavier than necessary.</p>
<h2 id="when-things-go-wrong" tabindex="-1">When Things Go Wrong</h2>
<p>Workflow problems tend to follow patterns. You should see them coming if you look for them.</p>
<h3 id="meetings-are-consuming-your-calendar" tabindex="-1">Meetings Are Consuming Your Calendar</h3>
<p>You're spending more time talking about process than building. Too many meetings or too many attendees in each. Audit your calendar. Which are necessary? Which are habitual? Cut what you don't need. Move what you can to async.</p>
<h3 id="simple-decisions-are-taking-weeks" tabindex="-1">Simple Decisions Are Taking Weeks</h3>
<p>You've applied enterprise-grade structure to lightweight decisions. Everything needs a full review. Create a &quot;fast track&quot; tier where simple changes get quick discussion and faster approval. People stop fearing the process.</p>
<h3 id="documentation-is-always-out-of-date" tabindex="-1">Documentation Is Always Out of Date</h3>
<p>Components ship before they're documented. You stopped enforcing documentation at ship time. Go back to your checklists. Make it a mandatory prerequisite like code review. If it feels like it's grinding everything to a halt, the problem isn't documentation—it's that you don't have enough time budgeted for it. Bake it into design and development.</p>
<h3 id="people-are-working-around-the-system" tabindex="-1">People Are Working Around the System</h3>
<p>They're building their own components or skipping approval. Your process is too slow or unclear. Listen. What's frustrating them? Why are they avoiding the system? Maybe your RFC takes too long. Maybe documentation requirements are unrealistic. Maybe nobody responds to their questions. Fix the underlying problem, not the symptom.</p>
<h3 id="new-team-members-take-months-to-onboard" tabindex="-1">New Team Members Take Months to Onboard</h3>
<p>Your process isn't documented well enough. They can't figure out how to contribute. Write it down. Make it scannable. Use real examples, not abstract principles. Show the actual templates and approved work samples.</p>
<h3 id="decisions-feel-inconsistent" tabindex="-1">Decisions Feel Inconsistent</h3>
<p>One proposal was approved, a similar one was rejected. Your decision criteria isn't clear or people aren't applying it consistently. Document what matters: &quot;Does this solve a problem multiple teams face? Does it fit our philosophy? Is it maintainable? Is the timing right?&quot; Make criteria explicit. Train decision-makers on consistent application. Everyone should work from the same playbook.</p>
<h2 id="building-toward-health" tabindex="-1">Building Toward Health</h2>
<p>The goal isn't the perfect workflow. It doesn't exist. The goal is a workflow
that works for your team right now and adapts as your team and the needs change.</p>
<p>Review your metrics. Which are moving in the right direction? If there's one that isn't, fix it.</p>
<p>Perhaps quarterly, survey the team. What's actually frustrating them? Do your
metrics match their experience? What's working well? What's still broken? Your
team knows better than anyone where the problems are and the friction is.</p>
<p>Create strategic review. Where were you a year ago? How much progress has been
made? Did any major problems emerge as you grew? And importantly, celebrate what
you've built. This can help you with planning on 'what next?'.</p>
<p>Workflows aren't static. They change as your team grows, your products evolve,
and you learn what works (and what doesn't). Don't be precious about your
process. Your process is a tool. If a tool doesn't work, get a new one.</p>
<p>The Design Systems that last aren't the ones with the most rigourous, tightend,
and sophisticated processes.</p>
<p>They're the ones where everyone understands how things work, trusts that the
process works, and feels safe contributing. That's what you should be building towards.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Modes and Themes That Stick - Building a Persistent Toggle Solution</title>
      <link href="https://www.alwaystwisted.com/articles/modes-and-themes-that-stick-building-a-persistent-toggle-solution.html"/>
      <updated>2026-06-30T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/modes-and-themes-that-stick-building-a-persistent-toggle-solution.html</id>
      <content type="html">
        <![CDATA[
        <p>Some websites that offer theming conflate two separate ideas. The <em>mode</em> (light or dark) and the <em>theme</em> (the accent colour or visual identity). <a href="https://www.alwaystwisted.com/articles/why-separating-themes-from-modes-transforms-your-design-system">They're not the same thing</a>. A user might want a dark interface with a blue accent, or a light interface with an orange one, and if you cram both into a single attribute, you end up with a mess of <code>dark-blue</code>, <code>light-blue</code>, <code>dark-orange</code>, and so on.</p>
<p>Keeping them in separate data attributes (<code>data-mode</code> and <code>data-theme</code>) keeps
the CSS clean and the logic independent, which is why the previous article
recommended this split for design systems. This article picks up from there. Now
that the two concepts are separated, how do you build controls that respect that
separation and persist user choices? I built this exact pattern on my own site
to handle that split elegantly. What follows is how it works, and what I
learned from living with it in production.</p>
<h2 id="the-html-structure-(layer-1)" tabindex="-1">The HTML Structure (Layer 1)</h2>
<p>These are mutually exclusive choices. Only one mode can be active, only one
theme can be active. That's what radio buttons are ideal for. Using native
<code>&lt;input type=&quot;radio&quot;&gt;</code> elements gives you the right semantics and keyboard
behaviour: arrow keys move between and select options, and Tab enters or leaves
the group.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>fieldset</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>control-group<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>legend</span><span class="token punctuation">></span></span>Colour mode<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>legend</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button-group<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mode<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>light<span class="token punctuation">"</span></span> <span class="token attr-name">data-mode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>light<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Light<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mode<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span> <span class="token attr-name">data-mode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Dark<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mode<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>system<span class="token punctuation">"</span></span> <span class="token attr-name">data-mode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>system<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>System<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>fieldset</span><span class="token punctuation">></span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>fieldset</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>control-group<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>legend</span><span class="token punctuation">></span></span>Accent theme<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>legend</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>button-group<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>red<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Red<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>blue<span class="token punctuation">"</span></span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>blue<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Blue<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>orange<span class="token punctuation">"</span></span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>orange<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Orange<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio-label<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>radio<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>purple<span class="token punctuation">"</span></span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>purple<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>Purple<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>fieldset</span><span class="token punctuation">></span></span></code></pre>
<p>The <code>&lt;fieldset&gt;</code> plus <code>&lt;legend&gt;</code> helps tell assistive tech what each controls. Each input is wrapped in a <code>&lt;label&gt;</code> with a <code>&lt;span&gt;</code> for the visible text. The input itself stays visually hidden with CSS, which lets you style the <code>&lt;span&gt;</code> to look like a button while keeping the native radio input functional underneath. Each input has both a <code>value</code> and a <code>data-*</code> attribute (redundant, but explicit). The browser automatically tracks which one is <code>checked</code> (ahem), so you don't need custom state management.</p>
<p>This markup is the foundation layer. Without any JavaScript, the inputs are keyboard-operable and semantically correct. Your CSS can style them, but the visual toggle won't change the page's appearance. That requires a different layer to set the data-mode and data-theme attributes. The foundation ensures graceful degradation; the full feature comes together with the script layers.</p>
<h2 id="the-three-layer-approach" tabindex="-1">The Three-Layer Approach</h2>
<p>This implementation is built as progressive enhancement. Each layer adds value, but none is required for the feature to work.</p>
<p>Layer 1 (the foundation) - HTML and CSS. The buttons exist, they're semantic, and your CSS can already set initial modes and themes. If the rest breaks, the page still renders sensibly.</p>
<p>Layer 2 (the enhancement) - A tiny blocking script in the head that runs before the page renders. It reads localStorage and applies the saved mode and theme before first paint, eliminating the flash of the wrong colour.</p>
<p>Layer 3 (the polish) - The deferred JavaScript that wires up interactivity, handles clicks, updates button states, and listens for OS preference changes. This layer makes the feature actually useful. But if it fails to load or execute, layers 1 and 2 still work.</p>
<h2 id="see-it-in-action" tabindex="-1">See It in Action</h2>
<p>Here's a working demo. Click the &quot;buttons&quot; to change modes and themes.</p>
<div class="at-g-feature">
<p class="codepen" data-height="700" data-pen-title="Theme and Mode Toggle Demo" data-version="2" data-default-tab="result" data-slug-hash="azpLzvW" data-user="sturobson" style="height: 700px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/editor/sturobson/pen/019f138e-9a52-7a4f-8fe8-39db4b632944">
  Theme and Mode Toggle Demo</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<h3 id="why-data-*-instead-of-parsing-ids" tabindex="-1">Why <code>data-*</code> instead of parsing IDs</h3>
<p>A (old) common shortcut is to encode the value in the element's <code>id</code> — <code>id=&quot;darkMode&quot;</code> — and then strip it back out in JS with something like <code>button.id.replace(&quot;Mode&quot;, &quot;&quot;).toLowerCase()</code>. It works, but it couples your <em>logic</em> to your <em>naming convention</em>: rename <code>darkMode</code> to <code>nightMode</code> and the stored value silently changes too.</p>
<p>Using an explicit <code>data-mode</code> / <code>data-theme</code> attribute keeps the value you care about separate from how you happen to select the element. It's a small thing, but it's the kind of decision that pays off the moment someone else touches the code.</p>
<h2 id="why-localstorage-(and-not-cookies-or-indexeddb)" tabindex="-1">Why localStorage (and not cookies or IndexedDB)</h2>
<p>There are three obvious places to persist a preference like this, and the choice matters more than it first appears.</p>
<ul>
<li>Cookies are sent to the server on every request. For a preference that's purely client-side, that's wasted bandwidth.</li>
<li>IndexedDB is built for structured, queryable, potentially large datasets. Storing two short strings in it is like renting a warehouse for your favourite mug.</li>
<li>localStorage is synchronous, simple, persists indefinitely, and is client-only (never sent to the server). For two tiny string values, it's the right-sized tool.</li>
</ul>
<p>The one real tradeoff with <code>localStorage</code> is the synchronous read but for two strings on page load, the cost is negligible.</p>
<h2 id="avoiding-the-flash%3A-a-blocking-head-script-(layer-2)" tabindex="-1">Avoiding the Flash: A Blocking Head Script (Layer 2)</h2>
<p>Before we get to the main logic, there's a problem to solve. If you wait for <code>DOMContentLoaded</code> to apply the saved mode, the browser will paint the <em>default</em> mode first and then snap to the user's preference a moment later. That 'flash of dark mode' (😅) can be jarring.</p>
<p>The fix is to apply <code>data-mode</code> and <code>data-theme</code> to the <code>&lt;html&gt;</code> element in a
tiny blocking inline script in the <code>&lt;head&gt;</code>, before the body renders.</p>
<p>I think this is the one place where a little render-blocking script is the
correct call. It's a few lines, it has no network cost, and it should run before first
paint:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">></span></span>
  <span class="token comment">&lt;!-- ...meta, etc... --></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
    <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token keyword">var</span> mode <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'system'</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> theme <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'theme'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'purple'</span><span class="token punctuation">;</span>
        <span class="token keyword">var</span> resolved <span class="token operator">=</span>
          mode <span class="token operator">===</span> <span class="token string">'system'</span>
            <span class="token operator">?</span> window<span class="token punctuation">.</span><span class="token function">matchMedia</span><span class="token punctuation">(</span><span class="token string">'(prefers-color-scheme: dark)'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>matches
              <span class="token operator">?</span> <span class="token string">'dark'</span>
              <span class="token operator">:</span> <span class="token string">'light'</span>
            <span class="token operator">:</span> mode<span class="token punctuation">;</span>
        <span class="token keyword">var</span> root <span class="token operator">=</span> document<span class="token punctuation">.</span>documentElement<span class="token punctuation">;</span>
        root<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-mode'</span><span class="token punctuation">,</span> resolved<span class="token punctuation">)</span><span class="token punctuation">;</span>
        root<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-theme'</span><span class="token punctuation">,</span> theme<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">/* storage unavailable - defaults in CSS will apply */</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">></span></span></code></pre>
<p>Note that this script resolves <code>&quot;system&quot;</code> to a concrete <code>light</code>/<code>dark</code> value for the attribute, but button state is handled later once the DOM is ready. Keep it small, keep it inline, and don't move it into an external file.</p>
<h2 id="setting-up-persistence-(layer-3)" tabindex="-1">Setting Up Persistence (Layer 3)</h2>
<p>With the 'flash of product A theme' handled, the deferred script takes care of everything else: keeping the buttons in sync, responding to clicks, saving choices, and reacting if the operating system's mode changes while the user is on the page. This is the layer that makes the feature interactive and truly useful, but it's also the layer that should gracefully degrade if JavaScript failed.</p>
<p>First, a small wrapper around <code>localStorage</code> so a single point of failure doesn't take the whole page down:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> storage <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token comment">// private mode, disabled storage, etc.</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function">set</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
      <span class="token comment">// Silently ignore. The page still works, the choice just won't persist.</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Now the main logic:</p>
<pre class="language-javascript"><code class="language-javascript">document<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'DOMContentLoaded'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> modeRadios <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>
    document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'input[name="mode"]'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> themeRadios <span class="token operator">=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>
    document<span class="token punctuation">.</span><span class="token function">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">'input[name="theme"]'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkQuery <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">matchMedia</span><span class="token punctuation">(</span><span class="token string">'(prefers-color-scheme: dark)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Restore saved state</span>
  <span class="token keyword">const</span> savedMode <span class="token operator">=</span> storage<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'system'</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> savedTheme <span class="token operator">=</span> storage<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'theme'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'purple'</span><span class="token punctuation">;</span>

  <span class="token function">applyMode</span><span class="token punctuation">(</span>savedMode<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">applyTheme</span><span class="token punctuation">(</span>savedTheme<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Wire up mode radios</span>
  modeRadios<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">radio</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    radio<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>checked<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> mode <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
        <span class="token function">applyMode</span><span class="token punctuation">(</span>mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
        storage<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Wire up theme radios</span>
  themeRadios<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">radio</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    radio<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>checked<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> theme <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
        <span class="token function">applyTheme</span><span class="token punctuation">(</span>theme<span class="token punctuation">)</span><span class="token punctuation">;</span>
        storage<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'theme'</span><span class="token punctuation">,</span> theme<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Listen for OS theme changes</span>
  darkQuery<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>storage<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'system'</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'system'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">applyMode</span><span class="token punctuation">(</span><span class="token string">'system'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">function</span> <span class="token function">applyMode</span><span class="token punctuation">(</span><span class="token parameter">mode</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> resolved <span class="token operator">=</span>
      mode <span class="token operator">===</span> <span class="token string">'system'</span> <span class="token operator">?</span> <span class="token punctuation">(</span>darkQuery<span class="token punctuation">.</span>matches <span class="token operator">?</span> <span class="token string">'dark'</span> <span class="token operator">:</span> <span class="token string">'light'</span><span class="token punctuation">)</span> <span class="token operator">:</span> mode<span class="token punctuation">;</span>

    document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-mode'</span><span class="token punctuation">,</span> resolved<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">updateRadioState</span><span class="token punctuation">(</span>modeRadios<span class="token punctuation">,</span> mode<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">applyTheme</span><span class="token punctuation">(</span><span class="token parameter">theme</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-theme'</span><span class="token punctuation">,</span> theme<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">updateRadioState</span><span class="token punctuation">(</span>themeRadios<span class="token punctuation">,</span> theme<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">function</span> <span class="token function">updateRadioState</span><span class="token punctuation">(</span><span class="token parameter">radios<span class="token punctuation">,</span> activeValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    radios<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">radio</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      radio<span class="token punctuation">.</span>checked <span class="token operator">=</span> radio<span class="token punctuation">.</span>value <span class="token operator">===</span> activeValue<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With radio inputs, the browser handles the mutual exclusivity for us. We just
read the <code>value</code> attribute and use the <code>checked</code> property. No need to toggle
classes or track state manually, the inputs do it for you.</p>
<h2 id="handling-%22system%22-mode-properly" tabindex="-1">Handling &quot;System&quot; Mode Properly</h2>
<p>This is the part that's easy to get subtly wrong. The naive approach would be - on load, check <code>prefers-color-scheme</code>, resolve it to <code>light</code> or <code>dark</code>, and save that. The problem is that you've now thrown away the user's actual intent. They didn't choose &quot;dark&quot;, they chose &quot;follow my system.&quot;. If they later switch their OS to light mode at sunset, your site stubbornly stays dark.</p>
<p>The fix is to store the intent, not the result. We save the literal string <code>&quot;system&quot;</code>, and only resolve it to a concrete mode at the moment we apply it. Three things make this work:</p>
<ol>
<li>The head script resolves <code>&quot;system&quot;</code> to light or dark for the initial paint, so there's no flash and no JavaScript reliance.</li>
<li><code>applyMode(&quot;system&quot;)</code> also resolves to light or dark, but <code>updateRadioState</code> still checks the System radio — so the UI reflects what the user actually chose.</li>
<li>The <code>darkQuery.addEventListener(&quot;change&quot;, …)</code> listener re-runs <code>applyMode</code> whenever the OS changes, but only if the user is still in system mode. Pick an explicit mode and the listener stays silent.</li>
</ol>
<h3 id="a-note-on-how-this-pairs-with-your-css" tabindex="-1">A note on how this pairs with your CSS</h3>
<p>There are two ways your CSS can respond to dark mode, and they don't mix well:</p>
<ul>
<li>Key everything off <code>data-mode</code> (e.g. <code>[data-mode=&quot;dark&quot;] { … }</code>) - This is what the code above assumes, and it's the approach I'd recommend — your JavaScript is the single source of truth, system resolution included, and you never get a mismatch between what the toggle says and what the page shows.</li>
<li>Key directly off the media query (<code>@media (prefers-color-scheme: dark)</code>) - If you do this, the browser handles system mode for you and the JS becomes redundant, but you lose the ability to override the system with an explicit light/dark choice, because the media query doesn't know about your toggle.</li>
</ul>
<p>Pick one. Mixing them leads to a bug where the page is dark, the toggle says light, and nobody can work out why. The <code>data-mode</code> approach is the one that lets a user override their system, which is usually the whole point of offering the toggle.</p>
<p>The result - a user in &quot;system&quot; mode sees the page change live as their OS
switches between light and dark, with no reload required, while a user who picks
an explicit mode keeps it regardless of what their OS does.</p>
<h2 id="styling-the-radio-inputs-(and-focus)" tabindex="-1">Styling the Radio Inputs (and Focus)</h2>
<p>Hide the native radio button visually and style the <code>&lt;span&gt;</code> to look like a button instead. When the input is checked, style the associated span. Keyboard users still interact with the hidden input and get focus indicators.</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Hide the radio input */</span>
<span class="token selector">.radio-label input</span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  <span class="token property">opacity</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Position and style the label */</span>
<span class="token selector">.radio-label</span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
  <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Style the span to look like a 'button' */</span>
<span class="token selector">.radio-label span</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.625rem 1rem<span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 2px solid <span class="token function">var</span><span class="token punctuation">(</span>--color-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-foreground<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 0.9rem<span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 500<span class="token punctuation">;</span>
  <span class="token property">transition</span><span class="token punctuation">:</span> all 0.2s ease<span class="token punctuation">;</span>
  <span class="token property">user-select</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Hover */</span>
<span class="token selector">.radio-label:hover span</span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary--opacity-90<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Checked */</span>
<span class="token selector">.radio-label input:checked + span</span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-light<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Focus */</span>
<span class="token selector">.radio-label input:focus-visible + span</span> <span class="token punctuation">{</span>
  <span class="token property">outline</span><span class="token punctuation">:</span> 3px solid <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">outline-offset</span><span class="token punctuation">:</span> 2px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="accessibility-notes" tabindex="-1">Accessibility Notes</h2>
<p>Theming controls are interactive UI, so they must work for everyone. Using native <code>&lt;input type=&quot;radio&quot;&gt;</code> elements with a <code>&lt;fieldset&gt;</code> and <code>&lt;legend&gt;</code> wrapper gives you keyboard navigation (arrow keys move between options, Tab enters or leaves the group), mutual exclusivity, and correct semantics automatically — don't rebuild this with <code>&lt;div&gt;</code>s and JavaScript state management.</p>
<p>The <code>&lt;span&gt;</code> text inside each <code>&lt;label&gt;</code> automatically becomes the input's accessible name. You don't need an <code>aria-label</code>; it would only override the visible text and create redundancy. Similarly, native radios are announced as &quot;checked&quot; or &quot;unchecked&quot; by assistive tech without any custom markup.</p>
<p>Keyboard users need a visible focus indicator. Using <code>:focus-visible</code> on the input (projected to the <code>+ span</code> with an outline) ensures this works for everyone who navigates by keyboard. Never suppress the browser's focus indicator without providing a replacement.</p>
<p>One thing native controls don't handle: colour contrast. The checked state applies <code>color: var(--color-light)</code> on <code>background-color: var(--color-accent)</code>, and the focus outline uses the same accent colour. Verify these meet WCAG requirements (text-on-background ≥ 4.5:1, focus indicator ≥ 3:1) for your specific values.</p>
<h2 id="gotchas-%26-things-to-watch-for" tabindex="-1">Gotchas &amp; Things to Watch For</h2>
<p><code>localStorage</code> can throw an exception in private/incognito modes or when storage is disabled entirely. It doesn't just return null. An unguarded <code>localStorage.getItem()</code> call will crash your script and leave the page unthemed. Both the head script and the <code>storage</code> wrapper are protected with <code>try/catch</code> so that worst case, preferences simply don't persist, but the page still works.</p>
<p>The head script must stay inline. Move it to an external file and you reintroduce the flash you eliminated. It's one of the rare cases where render-blocking is the correct choice.</p>
<p>Users clear site data regularly, so your fallbacks (<code>|| &quot;system&quot;</code>, <code>|| &quot;purple&quot;</code>) must be sensible defaults — they will execute. Similarly, don't mix <code>data-mode</code> CSS selectors with <code>prefers-color-scheme</code> media queries; pick one strategy or you'll end up with a page whose appearance disagrees with its toggle state.</p>
<p>If you're building this in a single-page app, remember to remove the media query <code>change</code> listener when the component unmounts, or you'll accumulate duplicates on each navigation.</p>
<h2 id="why-i-removed-this-from-my-site" tabindex="-1">Why I Removed This From My Site</h2>
<p>Despite the elegance of this approach, I eventually removed the theme toggle from my own site. The code had been sitting in my repo since 2022, and by the time I actually launched my site a few years later, it felt like legacy baggage. Not because it was broken, but because the maintenance overhead didn't justify the use. I had no real evidence that many people were actually using it, and the older the code got, the less confident I felt maintaining it. It became a feature I was shipping out of inertia rather than conviction.</p>
<p>The lesson for me was that just because you <em>can</em> persist preferences doesn't mean you <em>should</em>. Sometimes respecting system preferences alone is genuinely enough, and the simplicity of letting the browser handle mode entirely (<code>prefers-color-scheme</code> without a toggle) was actually a better trade-off than I'd given it credit for.</p>
<h2 id="closing-thoughts" tabindex="-1">Closing Thoughts</h2>
<p>What I like about this pattern is that it's progressive enhancement done quietly. The page has a sensible default mode and theme with no JavaScript at all. Add the head script, and it paints the right colours before first render. Add the deferred script, and it remembers choices and tracks the system in real time. Each layer improves the experience, but no single layer is load-bearing. Pull any one away and the page still works.</p>
<p>That's really the whole philosophy: persistence isn't about being clever, it's about respecting the choice a user already made and then getting out of their way. Store their intent, not your interpretation of it; fall back gracefully when you can't; and make sure the people navigating by keyboard or screen reader get the same consideration as everyone else. Do that, and &quot;it just remembers&quot; stops feeling like a feature and starts feeling like the way things should have worked all along.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Why Separating Themes from Modes Transforms Your Design System</title>
      <link href="https://www.alwaystwisted.com/articles/why-separating-themes-from-modes-transforms-your-design-system.html"/>
      <updated>2026-06-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/why-separating-themes-from-modes-transforms-your-design-system.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in 2022, while building out the start of this website's redesign (it took a
while), I wanted to use this new fangled CSS <code>color-mix()</code> function to generate an analogous colour palette,
one that would be easy to switch between and work in both light and dark modes.
But I needed to think about how I'd approach it.</p>
<p>I couldn't handle &quot;themes&quot; and &quot;modes&quot; as a single system.</p>
<p>They needed separate, independent control and logic.</p>
<h2 id="understanding-the-difference" tabindex="-1">Understanding the Difference</h2>
<h3 id="a-theme-is-a-colour-palette" tabindex="-1">A theme is a colour palette</h3>
<p>It's the choice between red, blue, orange, or purple. It's what helps give your
site its visual identity and typically aligns with brand guidelines (if they exist). A theme
is about the personality, it communicates who you are. Themes can also allow for
personalisation. It's nice to have.</p>
<h3 id="a-mode-is-a-brightness-preference" tabindex="-1">A mode is a brightness preference</h3>
<p>It's light, dark, or high contrast. Modes aren't optional in the same way. Some
users need dark mode to reduce eye strain or work in low-light environments.
Others require specific contrast ratios for readability. Modes are necessary for
accessibility.</p>
<h3 id="the-key-distinction" tabindex="-1">The key distinction</h3>
<p>A dark mode is a mode of a theme, not a theme itself. If you get this wrong, your code suffers.</p>
<p>A theme should work equally well or adapt in both light and dark modes. You
might keep the hue constant and adjust brightness only, or you might adjust the
hue itself depending on the mode, the separation gives you that choice. Because
themes and modes are independent controls, you can define a red theme that
stays pure red in both contexts, or a red theme that shifts its hue per mode if
the context demands it. It's can still be red. It can still match your brand guidelines.</p>
<h2 id="why-this-matters" tabindex="-1">Why This Matters</h2>
<p>When separated, users can select their favourite colour scheme independently from their brightness preference. Someone might love the orange theme but need dark mode for accessibility. That combination should work without special handling.</p>
<p>Accessibility features like dark mode or high-contrast mode shouldn't be tied to colour choices. By separating them, you unlock accessibility as a feature that exists independent of brand. Some users simply need dark mode. Others don't care about themes but depend on contrast modes. Your system should honour both choices without forcing them together.</p>
<p>For developers, separation should also create a clearer mental model and more
maintainable and adaptable code. When themes and modes are mixed, your selectors become
convoluted and your variables harder to reason.</p>
<p>Separation means each layer has a single job.</p>
<h2 id="at-design-system-scale---the-transformation" tabindex="-1">At Design System Scale - The Transformation</h2>
<p>This is where separation stops being a &quot;nice to have&quot; and becomes essential.
Without it, you will hit a wall.</p>
<p>Imagine you're building a design system used by five products. You've built dark
mode once, integrated it with your colour tokens. Now product two wants a new
theme. Product three needs a tweak to the high-contrast mode. Product four needs a seasonal
palette. Each of these requires rethinking how dark mode interacts with the new
colours. You're solving dark mode five times in five different ways. You're
authoring tokens five times. You're testing contrast five times.</p>
<p>As the system grows, this doesn't scale linearly, it will compound.</p>
<p>With separation, the architecture inverts. The mode layer becomes a shared
abstraction. One team defines &quot;light mode&quot;, &quot;dark mode&quot;, and &quot;high-contrast
mode&quot; once, and every new product inherits it for free. Products contribute only
their theme specific palettes.</p>
<p>Your token pipeline can split into two tracks. Maintainers own mode definitions,
products own their theme palettes. When you refine dark mode contrast, it ships
to every product simultaneously. You can test it once, and improvements propagate
everywhere.</p>
<p>Onboarding a new product drops from &quot;build a full theme and mode system&quot; to &quot;define our brand colours.&quot;</p>
<p>System wide upgrades happen at once. High-contrast mode, reduced motion,
seasonal palettes. These will become features that apply everywhere simultaneously. A
design system without this separation asks every consumer to solve brightness
accessibility independently.</p>
<p>That's not scalable. It's &quot;anti Design System&quot;.</p>
<p>Separating themes from modes is how you make it possible.</p>
<h2 id="how-i've-implemented-it" tabindex="-1">How I've Implemented It</h2>
<p>Separating themes and modes requires a simple architectural approach and I used data attributes for state and CSS variables for styling.</p>
<h3 id="setting-the-stage-with-data-attributes" tabindex="-1">Setting the stage with data attributes</h3>
<p>When a user selects a theme or mode, I set it on the HTML element like:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">data-theme</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>orange<span class="token punctuation">"</span></span> <span class="token attr-name">data-mode</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>This gives me two independent things I can control. JavaScript manages these attributes, and CSS reads them to determine what styles to apply.</p>
<h3 id="structuring-css-variables" tabindex="-1">Structuring CSS variables</h3>
<p>I can define base colours in the root:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-theme-red</span><span class="token punctuation">:</span> #ff3b30<span class="token punctuation">;</span>
  <span class="token property">--color-theme-blue</span><span class="token punctuation">:</span> #007aff<span class="token punctuation">;</span>
  <span class="token property">--color-theme-orange</span><span class="token punctuation">:</span> #ff9500<span class="token punctuation">;</span>

  <span class="token property">--color-white</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--color-black</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Then I use data attributes to switch which theme is active:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Default primary colour */</span>
<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-theme-orange<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* When user selects red theme */</span>
<span class="token selector">[data-theme='red']</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-theme-red<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">[data-theme='blue']</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-theme-blue<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>As an example for using modes, we can change the foreground and background
colours:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Simplified demo using semantic variables.
   In practice, I'd scope these to components instead.
*/</span>
<span class="token selector">[data-mode='light']</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-foreground</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color-scheme</span><span class="token punctuation">:</span> light<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">[data-mode='dark']</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-foreground</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Component applies the same hue, mode determines contrast */</span>
<span class="token selector">button</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">[data-mode='light'] button</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Vivid, high contrast against white background */</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>0 100% 50%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">[data-mode='dark'] button</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Same hue (red), but lightened to maintain contrast against black.
     In practice, this is automated with color-mix() or OKLCH. A future article covers that. */</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>0 100% 65%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="javascript-handles-the-switching" tabindex="-1">JavaScript handles the switching</h3>
<p>On the JavaScript side, I keep theme and mode logic separate:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">setTheme</span><span class="token punctuation">(</span><span class="token parameter">themeName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-theme'</span><span class="token punctuation">,</span> themeName<span class="token punctuation">)</span><span class="token punctuation">;</span>
  localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'theme'</span><span class="token punctuation">,</span> themeName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">setMode</span><span class="token punctuation">(</span><span class="token parameter">modeName</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-mode'</span><span class="token punctuation">,</span> modeName<span class="token punctuation">)</span><span class="token punctuation">;</span>
  localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">,</span> modeName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Two attributes, two functions. A separation of concerns.</p>
<h2 id="applying-the-variables-to-components" tabindex="-1">Applying the Variables to Components</h2>
<p>Once you've set up your variables and data attributes applying them to actual
elements is pretty straightforward:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">body</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-background<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-foreground<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">button</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-foreground<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-surface<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--color-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Every component variable references the same semantic variables referencing the
base values. When the user changes their theme or mode, all variables update at once.</p>
<h2 id="the-matrix-of-possibilities" tabindex="-1">The Matrix of Possibilities</h2>
<p>This is where the separation becomes powerful. With both <code>data-theme</code> and
<code>data-mode</code> attributes, you create a wild matrix of valid combinations:</p>
<ul>
<li>Red theme + Light mode</li>
<li>Red theme + Dark mode</li>
<li>Blue theme + Light mode</li>
<li>Blue theme + Dark mode</li>
<li>Orange theme + System preference</li>
<li>And so on.</li>
</ul>
<p>Each combination works automatically. Your CSS won't need special cases.</p>
<p>The theme handles personality, the mode handles brightness.</p>
<h2 id="handling-system-preferences" tabindex="-1">Handling System Preferences</h2>
<p>For system preference, JavaScript detects and applies the user's OS setting on first visit:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">detectSystemPreference</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> prefersDark <span class="token operator">=</span> window<span class="token punctuation">.</span><span class="token function">matchMedia</span><span class="token punctuation">(</span><span class="token string">'(prefers-color-scheme: dark)'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>matches<span class="token punctuation">;</span>
  <span class="token keyword">return</span> prefersDark <span class="token operator">?</span> <span class="token string">'dark'</span> <span class="token operator">:</span> <span class="token string">'light'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// On first visit, detect system preference</span>
<span class="token keyword">const</span> savedMode <span class="token operator">=</span> localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'mode'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">detectSystemPreference</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
document<span class="token punctuation">.</span>documentElement<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">'data-mode'</span><span class="token punctuation">,</span> savedMode<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Once set, the user can always override it by explicitly choosing a mode.</p>
<h2 id="structuring-it-all" tabindex="-1">Structuring It All</h2>
<p>Separating themes and modes makes accessibility more achievable because you can
evolve brightness support independently from brand. Add a high-contrast mode
without touching theme logic. Introduce a system wide preference fallback
without rebuilding every product's colour palette.</p>
<p>The separation also scales your codebase cleanly. Token governance can become
clear. Maintainers can own mode definitions, products can own brand palettes.
Testing becomes tractable, ou validate contrast matrices once per mode, not per
product. Adding a new theme becomes simpler. For users, the separation creates clarity. Changing
modes affects brightness. Changing themes affects personality.</p>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>The distinction between themes and modes transforms a design system from
something each product implements independently to something the system itself
solves and ships.</p>
<p>It's the difference between asking every team to build dark mode vs. giving them one to inherit.</p>
<p>For a single site, separation can improve your code organisation.</p>
<p>For a design system, it's the difference between scaling and fragmentation. Without it, each product forks mode logic.</p>
<p>The architecture is simple. The consequences of getting it wrong are not.</p>
<p>Your design system becomes genuinely reusable, and your products stop reinventing and bastardising the same wheels.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Building Your Design System Workflow - Rituals and Templates</title>
      <link href="https://www.alwaystwisted.com/articles/building-your-design-system-workflow-rituals-templates.html"/>
      <updated>2026-06-24T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/building-your-design-system-workflow-rituals-templates.html</id>
      <content type="html">
        <![CDATA[
        <p>Understanding what a good workflow looks like and actually building one are
totally different things. You know your proposals need a clear place to go. You know
decisions need a framework. You know that the documentation should be mandatory. But
how do you make all of that happen? What do people actually show up to? What do
you document? What tools do you use?</p>
<p>In this article we're going to walk through &quot;the work&quot;. The
specific rituals, templates, and tools you can implement this week to move from
&quot;we know we need a process&quot; to &quot;we have a process and it works.&quot;</p>
<p>It's meant to be practical enough to start with, flexible enough to adapt to your team's reality, and detailed enough that you don't have to guess what comes next.</p>
<h3 id="contribution---making-it-easy-to-propose" tabindex="-1">Contribution - Making It Easy to Propose</h3>
<p>Start with an <a href="#rfc-template">RFC (Request for Comments) template</a>. This is
scaffolding, not bureaucracy or the start of a benevolent dictatorship. The template captures what matters. The problem,
proposed solution, alternatives, effort estimate. Make it clear enough that
anyone can fill it out without needing permission to ask questions.</p>
<p>Designate one place where proposals live - a Slack channel, GitHub discussions,
or shared google doc. Make it explicit. One location where someone can ask
&quot;what's being reviewed?&quot; and get an answer in seconds. Keep proposals visible
with a spreadsheet, board, or table.</p>
<h3 id="review-and-approval---decision-making-structure" tabindex="-1">Review and Approval - Decision-Making Structure</h3>
<p>Form a <a href="https://designsystem.conde.io/resources/design-systems-council/">Design System Council</a>. A small group (4-6 people) that meets on a fixed schedule. Include a product design lead, engineering lead, design system lead, and 2-3 representatives from major product areas. This mix gives you perspective whilst staying small enough to actually make decisions.</p>
<p>Use a structured decision framework. Make it explicit so everyone knows what you're evaluating. &quot;Does this solve a real problem multiple teams face? Fit the system's philosophy? Maintainable? Right timing?&quot; Consistent criteria make decisions feel fair.</p>
<p>Run tight meetings. Spend about 10 minutes per proposal. 3 minutes for context and questions, 5 minutes for discussion, 2 minutes to decide. This discipline prevents meetings from running two hours. People come prepared. Decisions actually happen.</p>
<p>Document every significant decision in a <a href="#decision-log-template">Decision Log</a> or Architecture Decision Record. One page: what was decided, who was involved, alternatives considered, reasoning. This becomes your institutional memory and saves you from having to explain the same decision months later when someone asks &quot;why did we choose this?&quot; Keep these records searchable and centralized so anyone can find the reasoning behind how the system works.</p>
<p>Communicate decisions the same day. Don't make proposal authors wait. Include what's next: timeline if approved, conditions for deferral, reasoning if declined. Speed here builds trust.</p>
<h3 id="documentation---making-it-mandatory" tabindex="-1">Documentation - Making It Mandatory</h3>
<p>Make documentation part of your definition of done. A component doesn't ship until it's documented. Non-negotiable. This means it's budgeted, planned for, and not an afterthought.</p>
<p>Create <a href="#component-documentation-template">documentation templates</a> so people aren't starting from scratch guessing what's expected. For UI components, that means: what it is, when to use it, when not to use it, code examples, variants, accessibility notes, migration paths.</p>
<p>Assign clear ownership. A specific person is responsible. When they're on holiday, someone covers. It doesn't disappear into the void waiting for &quot;someone&quot; to do it. Ownership matters.</p>
<p>Start documenting during design, not after development. Capture thinking while it's fresh. The designer knows the intent, constraints, edge cases. Write it down immediately. Documentation is part of the design process, not a separate chore after the code's done.</p>
<h3 id="communication---structuring-the-cadence" tabindex="-1">Communication - Structuring the Cadence</h3>
<p>Build regular rituals. Not suggestions. Rhythm. When people know a meeting happens every Tuesday at 10 AM, they show up and plan around it. Consistency matters more than frequency. Informal feels flexible until it creates chaos.</p>
<p>Create structured Slack channels so conversations land in findable places instead of disappearing into noise:</p>
<ul>
<li><code>#design-system-announcements</code> for all your releases, breaking changes, major updates</li>
<li><code>#design-system-proposals</code> for any ideas and for RFCs</li>
<li><code>#design-system-support</code> for any questions and help needed</li>
<li><code>#design-system-feedback</code> for bugs and improvements, and feedback on changes.</li>
</ul>
<p>This should help prevent important conversations from being drowned out by an
accidental '@here has anyone seen my headphones?'.</p>
<h3 id="iteration---handling-ongoing-work" tabindex="-1">Iteration - Handling Ongoing Work</h3>
<p>Set up office hours. Weekly for 30-60 minutes. Product teams drop in to ask questions, request tweaks, report bugs. Low barrier. Remote-friendly. This creates a rhythm for feedback to flow up instead of disappearing.</p>
<p>Track feedback systematically. Feedback form, GitHub issues, spreadsheet. Something persistent. Convert Slack reports into tracked items. Log feature requests. Don't let feedback evaporate into nothing.</p>
<p>Review usage data monthly. Which components do products actually use? Which ones languish? Low adoption signals a problem. Either the component doesn't solve the right problem or people don't know it exists. Look at the data.</p>
<p>Maintain a public roadmap. &quot;We're improving Button next quarter, working on Tooltip in Q3.&quot; This signals the system is alive and evolving. Product teams see you're listening and responding.</p>
<p>Acknowledge feedback visibly. When someone requests a change, thank them by name when you implement it. When you fix a reported bug, let them know. People contribute more when they see their input actually matters.</p>
<h3 id="versioning-and-deprecation---managing-change-over-time" tabindex="-1">Versioning and Deprecation - Managing Change Over Time</h3>
<p>Use <a href="https://semver.org">semantic versioning</a>. MAJOR.MINOR.PATCH. MAJOR for breaking changes. MINOR for new features (backward compatible). PATCH for fixes. Everyone understands what each means.</p>
<p>Never ship breaking changes without warning. Give 2-3 releases of deprecation notices first. Show what's changing and how to migrate. Make it clear. Products stop trusting you if you break things without notice.</p>
<p>Write migration guides. Not just &quot;API changed.&quot; Show people how to update their code. Give examples. Provide tooling if possible. A codemod that automatically rewrites code saves weeks of work across all your products.</p>
<p>Communicate changes clearly in release notes. Consistent format. What's new, changed, fixed, deprecated, breaking. Be explicit about timelines so product teams can plan.</p>
<h2 id="communication-rituals---making-them-work" tabindex="-1">Communication Rituals - Making Them Work</h2>
<p>The rituals keep everything coordinated. They're not busywork. They're the moments when the system stays aligned instead of fragmenting into separate efforts.</p>
<h3 id="the-core-team-weekly" tabindex="-1">The Core Team Weekly</h3>
<p>The core team needs a regular rhythm. Same time every week prevents the &quot;I didn't know you were working on that&quot; moment. This is where the design system team synchronizes internally, removes blockers, and handles decisions that don't need broader input.</p>
<p>Gather the core team weekly at the same time. Start with metrics—five minutes on key numbers. Then fifteen minutes on WIP updates: what's each person on, what's blocking them. Spend twenty minutes on decisions that can't wait for the broader council. Close with five minutes looking ahead. Discipline keeps meetings focused—if it's not on the agenda 24 hours before, it doesn't happen.</p>
<h3 id="the-design-system-council" tabindex="-1">The Design System Council</h3>
<p>This is where governance happens. The council needs diverse voices so product leads go back and advocate. Adoption happens naturally because they were part of the decision. By including representatives from different areas of the product, you distribute ownership. It stops being something the design system team maintains and becomes something the whole organisation shapes.</p>
<p>Start with five minutes for announcements. Spend forty minutes on proposal reviews—handle 2-3 RFCs, ten minutes each. Ten minutes on open discussion. Five minutes on action items. Send pre-reads 48 hours before: one page per proposal. If there's no pre-read, defer it.</p>
<p>Use a consistent decision framework so every proposal gets evaluated the same way. Ask four questions: Does this solve a real problem multiple teams face? Does it fit the system's philosophy? Is it maintainable? Is the timing right? Yes to all four means green light. No to any means discuss what would change that answer. This transparency makes decisions feel fair because everyone knows what you're measuring against.</p>
<h3 id="design-critique" tabindex="-1">Design Critique</h3>
<p>Improves work through feedback. The format creates safety so people share unfinished work early, when feedback changes direction instead of late investments. Start with context: explain what you're working on and what feedback you need. Then silent review for five minutes. Clarifying questions for five. Feedback using &quot;I like, I wish, I wonder&quot; for twenty. Finally, five minutes on next steps. Keep it synchronous—tone matters, and text makes critique feel harsher than intended.</p>
<h3 id="design-to-engineering-handoff" tabindex="-1">Design to Engineering Handoff</h3>
<p>Critical conversation. An hour upfront saves a week of rework. Design walkthrough covering variants, states, interactions. Ten minutes on technical discussion: props, tokens, event handling, edge cases, constraints. Five minutes on Q&amp;A. Five minutes reaching agreement on scope and timeline. Get alignment before building starts.</p>
<h3 id="monthly-demo" tabindex="-1">Monthly Demo</h3>
<p>Shows organisational value and signals the system is alive. Run for thirty minutes. Fifteen minutes demoing what shipped—show 2-3 components and the problems they solve. Five minutes on what's coming. Five minutes spotlighting a product team. Five minutes Q&amp;A. Record it so people who can't attend still get the message.</p>
<h2 id="templates-that-reduce-friction" tabindex="-1">Templates That Reduce Friction</h2>
<p>Templates are scaffolding. They make it easy for people to contribute the right information without overthinking structure. The RFC template isn't about bureaucracy. It's about making sure proposers think through their ideas and reviewers have what they need to decide.</p>
<h3 id="rfc-template" tabindex="-1">RFC Template</h3>
<p>An RFC template captures what matters: What problem? Who has it? Why this solution? What's the cost? Without requiring a 20-page document.</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> RFC: [Component Name]</span>

<span class="token title important"><span class="token punctuation">##</span> Status</span>

<span class="token list punctuation">-</span> [ ] Draft
<span class="token list punctuation">-</span> [ ] In Review
<span class="token list punctuation">-</span> [ ] Approved
<span class="token list punctuation">-</span> [ ] Declined

<span class="token title important"><span class="token punctuation">##</span> Problem Statement</span>

What problem does this component solve? Who experiences it? Include 1-2 specific examples from your products.

<span class="token title important"><span class="token punctuation">##</span> Proposed Solution</span>

Describe the component. Include:

<span class="token list punctuation">-</span> What it looks like (sketch, screenshot, or Figma link)
<span class="token list punctuation">-</span> How it behaves
<span class="token list punctuation">-</span> What props/variants exist
<span class="token list punctuation">-</span> Accessibility considerations

<span class="token title important"><span class="token punctuation">##</span> Alternatives Considered</span>

<span class="token list punctuation">-</span> What other approaches did you think about?
<span class="token list punctuation">-</span> Why does the proposed solution win?

<span class="token title important"><span class="token punctuation">##</span> Impact Assessment</span>

<span class="token list punctuation">-</span> How many products/teams would use this?
<span class="token list punctuation">-</span> Does this replace or change anything existing?
<span class="token list punctuation">-</span> Rough effort estimate for design, development, documentation

<span class="token title important"><span class="token punctuation">##</span> Open Questions</span>

<span class="token list punctuation">-</span> What still needs to be decided?
<span class="token list punctuation">-</span> Are there technical unknowns?
<span class="token list punctuation">-</span> Dependencies on other work?

<span class="token title important"><span class="token punctuation">##</span> Timeline</span>

When would you want this shipped? What's the critical path?</code></pre>
<h3 id="decision-log-template" tabindex="-1">Decision Log Template</h3>
<p>Decisions are institutional memory. Without them, knowledge walks out the door when people leave. Someone asks &quot;why is it designed this way?&quot; and nobody can answer. Decision logs let teams understand not just what was decided, but why.</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> Decision: [What Was Decided]</span>

<span class="token bold"><span class="token punctuation">**</span><span class="token content">Date</span><span class="token punctuation">**</span></span>: 2026-06-17
<span class="token bold"><span class="token punctuation">**</span><span class="token content">Decision Makers</span><span class="token punctuation">**</span></span>: [Names of who decided]
<span class="token bold"><span class="token punctuation">**</span><span class="token content">Proposal</span><span class="token punctuation">**</span></span>: Link to RFC or description

<span class="token title important"><span class="token punctuation">##</span> Decision</span>

[One clear sentence: what was approved/rejected/deferred]

<span class="token title important"><span class="token punctuation">##</span> Rationale</span>

[Why? What criteria mattered? What trade-offs were made?]

<span class="token title important"><span class="token punctuation">##</span> Alternatives Considered</span>

<span class="token list punctuation">-</span> <span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">Alternative 1</span><span class="token punctuation">]</span><span class="token punctuation">:</span> Why</span> this wasn't chosen
<span class="token list punctuation">-</span> <span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">Alternative 2</span><span class="token punctuation">]</span><span class="token punctuation">:</span> Why</span> this wasn't chosen

<span class="token title important"><span class="token punctuation">##</span> Implications</span>

[What happens now? Who does what? Timeline?]

<span class="token title important"><span class="token punctuation">##</span> Dependencies</span>

[Does this depend on other work? What depends on this?]

<span class="token title important"><span class="token punctuation">##</span> Revisit?</span>

[Is this decision ever revisited? When? Based on what?]</code></pre>
<h3 id="release-notes-template" tabindex="-1">Release Notes Template</h3>
<p>Clear release notes help products understand what changed and whether they need to update. Unclear notes? They skip it. Your fixes don't reach them. Clear notes drive adoption.</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> v2.4.0 - Released 2026-06-17</span>

<span class="token title important"><span class="token punctuation">##</span> ✨ New</span>

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Component Name</span><span class="token punctuation">**</span></span>: Brief description of the new component
  <span class="token list punctuation">-</span> Use when: specific use cases where this makes sense
  <span class="token list punctuation">-</span> Replace: any component this replaces (if applicable)

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Button</span><span class="token punctuation">**</span></span>: Added <span class="token code-snippet code keyword">`size="small"`</span> variant
  <span class="token list punctuation">-</span> Use when: compact layouts where regular button is too large

<span class="token title important"><span class="token punctuation">##</span> 🔄 Changed</span>

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Card</span><span class="token punctuation">**</span></span>: Increased padding from 16px to 20px to match new spacing scale
  <span class="token list punctuation">-</span> Why: improves visual breathing room and aligns with design tokens
  <span class="token list punctuation">-</span> Migration: no code changes needed, automatic

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Tooltip</span><span class="token punctuation">**</span></span>: Repositioned to avoid viewport edge (now uses adaptive positioning)
  <span class="token list punctuation">-</span> Why: tooltips were getting cut off near edges
  <span class="token list punctuation">-</span> Migration: no code changes needed

<span class="token title important"><span class="token punctuation">##</span> 🐛 Fixed</span>

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Form Field</span><span class="token punctuation">**</span></span>: Fixed focus state in Safari (was missing outline)
<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">Icon Button</span><span class="token punctuation">**</span></span>: Fixed alignment issue on Windows (was 1px off)

<span class="token title important"><span class="token punctuation">##</span> 📦 Deprecated</span>

<span class="token list punctuation">-</span> <span class="token bold"><span class="token punctuation">**</span><span class="token content">OldButton</span><span class="token punctuation">**</span></span>: Use Button component instead
  <span class="token list punctuation">-</span> Timeline: will be removed in v3.0 (estimated 2026-09-17)
  <span class="token list punctuation">-</span> Migration: <span class="token url">[<span class="token content">See migration guide</span>](<span class="token url">link-to-guide</span>)</span>
  <span class="token list punctuation">-</span> Questions?: Reply in #design-system-support

<span class="token title important"><span class="token punctuation">##</span> 🔗 Additional Resources</span>

<span class="token list punctuation">-</span> Full changelog: [link]
<span class="token list punctuation">-</span> Migration guide: [link]
<span class="token list punctuation">-</span> Demo video: [link]</code></pre>
<h3 id="component-documentation-template" tabindex="-1">Component Documentation Template</h3>
<p>This lives in Storybook or your docs. It's the interface between system and products. Make it clear and comprehensive.</p>
<pre class="language-markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> Component Name</span>

<span class="token title important"><span class="token punctuation">##</span> Overview</span>

One sentence description. What does this do?

<span class="token title important"><span class="token punctuation">##</span> When to Use</span>

<span class="token list punctuation">-</span> Use when: specific situation
<span class="token list punctuation">-</span> Use when: specific situation
<span class="token list punctuation">-</span> Don't use when: don't use for this

<span class="token title important"><span class="token punctuation">##</span> Usage</span>

<span class="token title important"><span class="token punctuation">###</span> Basic Example</span>

<span class="token code"><span class="token punctuation">```</span><span class="token code-language">html</span>
<span class="token code-block language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>ds-button<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span></span>
<span class="token punctuation">```</span></span>

<span class="token code"><span class="token punctuation">```</span><span class="token code-language">css</span>
<span class="token code-block language-css"><span class="token selector">.ds-button</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 8px 16px<span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.ds-button:disabled</span> <span class="token punctuation">{</span>
  <span class="token property">opacity</span><span class="token punctuation">:</span> 0.5<span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> not-allowed<span class="token punctuation">;</span>
<span class="token punctuation">}</span></span>
<span class="token punctuation">```</span></span>

<span class="token code"><span class="token punctuation">```</span><span class="token code-language">js</span>
<span class="token code-block language-js"><span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.ds-button'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
button<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'click'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Button clicked'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="token punctuation">```</span></span>

<span class="token title important"><span class="token punctuation">###</span> All Variants</span>

[Show each variant with code example]

<span class="token title important"><span class="token punctuation">##</span> Props</span>

<span class="token table"><span class="token table-header-row"><span class="token punctuation">|</span><span class="token table-header important"> Prop     </span><span class="token punctuation">|</span><span class="token table-header important"> Type    </span><span class="token punctuation">|</span><span class="token table-header important"> Required </span><span class="token punctuation">|</span><span class="token table-header important"> Description                       </span><span class="token punctuation">|</span>
</span><span class="token table-line"><span class="token punctuation">|</span> <span class="token punctuation">:-------</span> <span class="token punctuation">|</span> <span class="token punctuation">:------</span> <span class="token punctuation">|</span> <span class="token punctuation">:------:</span> <span class="token punctuation">|</span> <span class="token punctuation">:--------------------------------</span> <span class="token punctuation">|</span>
</span><span class="token table-data-rows"><span class="token punctuation">|</span><span class="token table-data"> label    </span><span class="token punctuation">|</span><span class="token table-data"> string  </span><span class="token punctuation">|</span><span class="token table-data">   yes    </span><span class="token punctuation">|</span><span class="token table-data"> The component label               </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> disabled </span><span class="token punctuation">|</span><span class="token table-data"> boolean </span><span class="token punctuation">|</span><span class="token table-data">    no    </span><span class="token punctuation">|</span><span class="token table-data"> Whether the component is disabled </span><span class="token punctuation">|</span>
</span></span>
<span class="token title important"><span class="token punctuation">##</span> Accessibility</span>

<span class="token list punctuation">-</span> Keyboard: [How do you interact with keyboard?]
<span class="token list punctuation">-</span> Screen readers: [What announcements are made?]
<span class="token list punctuation">-</span> ARIA: [Any special attributes?]

<span class="token title important"><span class="token punctuation">##</span> Common Patterns</span>

[Show 2-3 real-world usage examples with code]

<span class="token title important"><span class="token punctuation">##</span> Related Components</span>

<span class="token list punctuation">-</span> <span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">Component A</span><span class="token punctuation">]</span><span class="token punctuation">:</span> Use</span> instead when...
<span class="token list punctuation">-</span> <span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">Component B</span><span class="token punctuation">]</span><span class="token punctuation">:</span> Use</span> together with...

<span class="token title important"><span class="token punctuation">##</span> Changelog</span>

<span class="token list punctuation">-</span> v2.4.0: Added size="small" variant
<span class="token list punctuation">-</span> v2.3.0: Initial release</code></pre>
<h2 id="implementation%3A-getting-started-realistically" tabindex="-1">Implementation: Getting Started Realistically</h2>
<p>You don't need everything in place before you start. It's better to begin with something rough that actually works than to wait for everything to be perfect. The phases below happen in sequence, but the timeline depends on your team's reality. Some teams move through these quickly. Others take longer. That's fine.</p>
<h3 id="audit-your-current-state" tabindex="-1">Audit your current state</h3>
<p>Shadow contributions. Map what's working and what creates friction. Interview team members about where they lose time. Look for patterns: Is feedback scattered across multiple channels? Are decisions made informally? Do new team members not know how to propose ideas? These aren't separate problems—they're signals about where the workflow is breaking. Get alignment on what's broken before you redesign.</p>
<h3 id="design-the-workflows-you-want" tabindex="-1">Design the workflows you want</h3>
<p>Workshop with the core team. If you could start from scratch, what would it look like? Think through the rituals you need, the templates that would help, the communication channels that matter. Prioritise high-impact, low-effort changes first. Assign an owner to each pillar.</p>
<h3 id="pilot-with-one-component" tabindex="-1">Pilot with one component</h3>
<p>Finalise your RFC template and contribution guidelines. Set up the Design System Council. Pick one medium-complexity component and put it through your complete process: ideation to release. Follow your own process. What breaks? What feels good? Learn from it. This teaches you whether your workflows actually work before you ask the whole team to adopt them.</p>
<h3 id="refine-based-on-what-you-learned" tabindex="-1">Refine based on what you learned</h3>
<p>Bake pilot learnings into everything. Update templates that missed information. Document distinctions between rituals if people were confused. Write contribution guidelines with examples. Build your full template library. Crystallise what you learned so you're not teaching the same lessons repeatedly.</p>
<h3 id="launch-to-the-team" tabindex="-1">Launch to the team</h3>
<p>Present the pilot success. Share documentation everywhere. Offer office hours for questions. Be available for quick fixes and iteration. People won't adopt things that feel mysterious. Make it accessible.</p>
<h3 id="expand-organisation-wide" tabindex="-1">Expand organisation-wide</h3>
<p>Survey the team on how the new workflows are working. Review metrics. What's improving? What's still broken? Make adjustments based on feedback. Announce to the broader organisation. Establish a quarterly review rhythm so you continuously refine.</p>
<h3 id="iterate-continuously" tabindex="-1">Iterate continuously</h3>
<p>Workflows evolve with team size. What works at 5 won't at 15. Rituals become rote. Frameworks hit edge cases. That's normal, not failure. Listen to what people actually do: which rituals they attend, which templates they use, what breaks. When something isn't working, change it. Your first version won't be perfect. Neither will the next. Establish a regular rhythm—quarterly or semi-annually—to review metrics, gather feedback, and refine.</p>
<h2 id="running-it-%26-making-it-stick" tabindex="-1">Running It &amp; Making It Stick</h2>
<p>Implementation is easy. Consistency is hard. People are busy. New processes feel like extra work before they feel like relief. Here's what actually makes them stick.</p>
<p>Make it visible. Decisions, roadmap, metrics all public. Transparency builds trust.</p>
<p>Celebrate wins publicly. When someone proposes, thank them. Demo new components. Make them heroes. Visibility drives participation.</p>
<p>Respond quickly. Don't let RFCs sit for weeks. Fast feedback, even just &quot;reviewing in council Tuesday&quot;, trains people to participate.</p>
<p>Refine ruthlessly. What's not working? Fix it. Don't be precious about processes. They're tools. If a tool doesn't work, you get a new one. Your team will tell you what's broken if you ask. Listen.</p>
<p>Measure something. Pick one metric. Contribution volume, decision time, adoption. Track it monthly. Show improvement. People believe systems that demonstrably work.</p>
<p>Remember the human cost. Clear workflows don't just save time. They save people from exhaustion. From the feeling of working against the system instead of with it. From wondering if they're allowed to contribute. That matters. Keep that in mind when you're debating whether a ritual is worth the time.</p>
<h2 id="what-comes-next" tabindex="-1">What Comes Next</h2>
<p>Once you've built the operational infrastructure (rituals, templates, tools), you've solved the immediate problem: the chaos. People know how to contribute. Decisions happen. Communication flows. But building a workflow and maintaining one are different challenges.</p>
<p>Workflows start to crack over time. What worked for 5 people breaks at 15. A ritual becomes rote. A framework hits edge cases. These aren't failures. They're growth. Metrics tell you when things are breaking. Common mistakes become obvious in hindsight. Scaling strategies that work in one context fail in another. When they break, you troubleshoot and refine.</p>
<p>These should be the patterns that distinguish your design system that will last from ones that collapse under their own weight.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (Part 17) - How Colour Works with the DTCG Color Module</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-17.html"/>
      <updated>2026-06-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-17.html</id>
      <content type="html">
        <![CDATA[
        <p>Colour can drive branding, visual hierarchy, theming, and accessibility in any
design system. It's also where workflows tend to break down: colour shows up as
hex in Figma, as RGB in one tool, as HSL in another. Every tool has its own
representation, and nothing speaks the same language.</p>
<p>The <a href="https://www.designtokens.org">DTCG</a> spec fixes that. Instead of treating colour as loose strings, the spec structures it as typed tokens with explicit, machine-readable data.</p>
<h2 id="why-colour-needs-a-spec" tabindex="-1">Why colour needs a spec</h2>
<p>A hex value like <code>#bada55</code> will show you what colour ended up on screen. But it won't tell you how it got there or what it can become. You can work with hex alone, but you're limited.</p>
<p>Without the colour space, you don't know if it was authored in sRGB or whether it's safe for wide-gamut displays. Without that context, a tool can't reliably generate tints, shades, or accessible contrast variants. It's just a number with no context.</p>
<p>The spec changes that. Structured colour gives tools actual data to work with, not guesses. It makes your colour system robust enough to scale.</p>
<h2 id="the-basic-dtcg-color-token-shape" tabindex="-1">The basic DTCG color token shape</h2>
<p>In the spec, colour tokens use:</p>
<ul>
<li><code>$type: &quot;color&quot;</code> - tells the system this is a colour token</li>
<li><code>$value</code> - the actual colour data with structure</li>
</ul>
<p>A simple example looks like this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"srgb"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.73</span><span class="token punctuation">,</span> <span class="token number">0.86</span><span class="token punctuation">,</span> <span class="token number">0.33</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"alpha"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="what-each-part-does" tabindex="-1">What each part does</h3>
<p><strong><code>colorSpace</code></strong> - tells tools which colour space you're using (sRGB, OKLCH, HSL, etc.). Tools need this to interpret and convert the colour correctly.</p>
<p><strong><code>components</code></strong> - the actual colour values in that space, as three numbers from 0 to 1. In sRGB, that's [red, green, blue]. In OKLCH, it's [lightness, chroma, hue]. In HSL: [hue, saturation, lightness].</p>
<p><strong><code>alpha</code></strong> - opacity from 0 (transparent) to 1 (opaque). Optional (if you don't include it, tools assume 1 (fully opaque)).</p>
<p><strong><code>hex</code></strong> - the fallback for legacy tools that don't understand colour spaces. Optional, but useful. It's not your source of truth anymore it's just a convenient output format for systems that need it.</p>
<p>The payoff: this structure turns colour into readable data. Your build system can now parse the colour space, generate variants, calculate contrast, and output to any format you need. Hex was always just one representation. Now it's one of many outputs.</p>
<h2 id="why-the-values-are-0-to-1" tabindex="-1">Why the values are 0 to 1</h2>
<p>The spec uses values from <code>0</code> to <code>1</code> instead of <code>0</code> to <code>255</code> because normalised ranges are easier for calculations, conversions, and interpolation. You get decimal precision too, <code>0.67</code> or <code>0.742</code> instead of rounding to integers. That matters for automated colour processing and theming systems.</p>
<h2 id="supported-colour-spaces" tabindex="-1">Supported colour spaces</h2>
<p>For web development, focus on these. They're what your teams will actually use:</p>
<ul>
<li><a href="https://www.w3.org/TR/css-color-4/#rgb">sRGB</a> - the web baseline, backwards compatible with <code>#hex</code> and <code>rgb()</code></li>
<li><a href="https://www.w3.org/TR/css-color-4/#the-hsl-notation">HSL</a> - familiar from CSS, widely used in design tools</li>
<li><a href="https://www.w3.org/TR/css-color-4/#ok-lch">OKLCH</a> - perceptual space, ideal for ramps and theming</li>
<li><a href="https://www.w3.org/TR/css-color-4/#ok-lab">OKLAB</a> - perceptual alternative to CIELAB, better for design automation</li>
<li><a href="https://www.w3.org/TR/css-color-4/#display-p3">Display P3</a> - wide-gamut colours for modern displays</li>
<li><a href="https://www.w3.org/TR/css-color-4/#the-hwb-notation">HWB</a> - CSS standard, less common but available</li>
<li><a href="https://www.w3.org/TR/css-color-4/#linear-rgb">sRGB linear</a> - for technical/scientific calculations</li>
</ul>
<p>The DTCG spec also supports other colour spaces for specialized workflows: <a href="https://www.w3.org/TR/css-color-4/#lab-colors">CIELAB</a>, <a href="https://www.w3.org/TR/css-color-4/#lch-colors">LCH</a>, <a href="https://www.w3.org/TR/css-color-4/#adobe-rgb">A98 RGB</a>, <a href="https://www.w3.org/TR/css-color-4/#prophoto-rgb">ProPhoto RGB</a>, <a href="https://www.w3.org/TR/css-color-4/#rec2020">Rec. 2020</a>, and <a href="https://www.w3.org/TR/css-color-4/#xyz-d65">XYZ variants</a>. These serve professional print, broadcast, or colour science use cases. You likely won't need them, but they're there if your workflow does.</p>
<h2 id="the-none-keyword" tabindex="-1">The <code>none</code> keyword</h2>
<p>When a colour component doesn't apply, use <code>none</code>. In HSL, saturation for a neutral white is meaningless, so you'd write <code>[&quot;none&quot;, 0, 100]</code> instead. This matters for colour mixing and interpolation: <code>none</code> means &quot;skip this&quot;, while <code>0</code> means &quot;zero value&quot;. The distinction is subtle but critical.</p>
<h2 id="how-to-work-with-tools-that-only-understand-hex" tabindex="-1">How to work with tools that only understand hex</h2>
<p>Many tools still prefer, or only accept, hex. Some Figma workflows are easiest with hex. Some legacy systems won't budge.</p>
<p>That's fine. The spec lets you store the source colour structurally while exporting hex as a fallback.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"alpha"</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>A tool that only understands hex uses <code>#bada55</code>. A tool that understands the
full token can do much more like generate variants, handle colour space conversions,
support wide gamut. Your spec-based token becomes the source of truth. Hex
becomes one of many outputs.</p>
<h2 id="why-structured-colour-scales-with-your-system" tabindex="-1">Why structured colour scales with your system</h2>
<p>If colour is only stored as hex, future tools inherit that limitation. They can't preserve wide-gamut output, can't interpolate reliably, can't generate variants from intent.</p>
<p>Structured colour unlocks the real work: accurate colour conversion, perceptual editing, intelligent interpolation, and variant generation. Your tokens don't fossilise, they evolve with your platform and tools.</p>
<h2 id="why-oklch-matters-for-your-workflow" tabindex="-1">Why OKLCH matters for your workflow</h2>
<p>If you're authoring colour systems in 2026, OKLCH is where the industry is moving. Material Design 3, Parity, Carbon Design, and other thought leaders have standardized on it. The reason is simple: it's the only perceptual space where equal steps feel visually equal. That makes it ideal for ramps, tint systems, theme generation, and automated accessibility.</p>
<p>Here's why it changes your workflow:</p>
<p><strong>In sRGB</strong>, if you want a darker yellow-green, you'd reduce all three RGB components. But the visual darkness doesn't decrease evenly, a yellow-green at <code>[0.73, 0.86, 0.33]</code> and a shade at <code>[0.36, 0.43, 0.16]</code> don't look like consistent steps. Your eye doesn't perceive them as such.</p>
<p><strong>In OKLCH</strong>, lightness is the first component. Reduce it by <code>0.1</code> and you get a proportionally darker colour every time. Your ramps look consistent, predictable, and maintainable. This is why automation works. This is why major design systems chose it.</p>
<h2 id="migrating-from-hex-to-structured-colour" tabindex="-1">Migrating from hex to structured colour</h2>
<p>If you have an existing hex-based system, you don't need to rewrite everything
at once. Start by picking a target colour space. OKLCH for most workflows, sRGB
if you need maximum compatibility.</p>
<p>The tool below converts your design token JSON from simple hex values into fully structured colour tokens. Feed it your existing token file (with just name and hex value), pick your target colour space, and it generates the complete DTCG-spec output with colour space, components, and fallback hex.</p>
<div class="at-g-feature">
<p class="codepen" data-height="700" data-pen-title="Design Tokens Colour Module Changer" data-version="2" data-default-tab="result" data-slug-hash="LExymZM" data-user="sturobson" data-token="e1797ee90b140ddec9e7607be0ebd27f" style="height: 700px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/editor/sturobson/pen/019ef3e3-affd-79b5-abc7-6f7dc0c4eb78/e1797ee90b140ddec9e7607be0ebd27f">
  Design Tokens Colour Module Changer</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<p>You now have tokens with full colour space metadata. Update your build to output both the hex and the colour space structure. Your old tools keep working. Your new tools get more. From here, author new tokens: ramps, semantic aliases, component tokens in your chosen space from the start. You extend your system instead of forking it.</p>
<h2 id="what-else-can-we-do-with-structured-colour%3F" tabindex="-1">What else can we do with structured colour?</h2>
<p>Once your colours are structured, automation becomes possible.</p>
<h2 id="1.-generate-colour-ramps-automatically" tabindex="-1">1. Generate colour ramps automatically</h2>
<p>This is one of the highest-value uses of structured colour. Once your base colour is defined in a perceptual space, a transform can generate systematic palettes automatically.</p>
<h3 id="defining-a-colour-for-ramp-generation" tabindex="-1">Defining a colour for ramp generation</h3>
<p>Start with a base colour token marked for automation using <code>$extensions</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"com.tokens.rampGenerator"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"generateRamp"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token property">"steps"</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span>
            <span class="token property">"lightnessShift"</span><span class="token operator">:</span> <span class="token number">0.08</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The extension metadata tells your build: generate 10 steps by shifting lightness by 0.08 each iteration.</p>
<h3 id="style-dictionary-transformer" tabindex="-1">Style Dictionary transformer</h3>
<p>A Style Dictionary transform reads this and generates the full ramp:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// transforms/generateColorRamp.js</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'generateColorRamp'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">match</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.tokens.rampGenerator'</span><span class="token punctuation">]</span><span class="token operator">?.</span>generateRamp<span class="token punctuation">,</span>
  <span class="token function-variable function">transform</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> config <span class="token operator">=</span> token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.tokens.rampGenerator'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> <span class="token punctuation">[</span>lightness<span class="token punctuation">,</span> chroma<span class="token punctuation">,</span> hue<span class="token punctuation">]</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">.</span>components<span class="token punctuation">;</span>

    <span class="token keyword">const</span> ramp <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> config<span class="token punctuation">.</span>steps<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> step <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> stepNumber <span class="token operator">=</span> step <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> newLightness <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>
        <span class="token number">0</span><span class="token punctuation">,</span>
        Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> lightness <span class="token operator">-</span> config<span class="token punctuation">.</span>lightnessShift <span class="token operator">*</span> <span class="token punctuation">(</span>config<span class="token punctuation">.</span>steps <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>

      ramp<span class="token punctuation">[</span>stepNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">$type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">$value</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">colorSpace</span><span class="token operator">:</span> <span class="token string">'oklch'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>newLightness<span class="token punctuation">,</span> chroma<span class="token punctuation">,</span> hue<span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token literal-property property">hex</span><span class="token operator">:</span> <span class="token function">oklchToHex</span><span class="token punctuation">(</span>newLightness<span class="token punctuation">,</span> chroma<span class="token punctuation">,</span> hue<span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> ramp<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This produces:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"lime"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.94</span><span class="token punctuation">,</span> <span class="token number">0.08</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#f2f9e8"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.89</span><span class="token punctuation">,</span> <span class="token number">0.12</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#e8f4d1"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.83</span><span class="token punctuation">,</span> <span class="token number">0.15</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#dceeb9"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"900"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.48</span><span class="token punctuation">,</span> <span class="token number">0.14</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#5a7a1f"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Once generated, you can export to hex, CSS variables, or platform-specific formats. The ramp stays consistent across your entire system.</p>
<h3 id="simpler-approach%3A-define-one-colour%2C-transform-the-rest" tabindex="-1">Simpler approach: define one colour, transform the rest</h3>
<p>If that feels like too much metadata, you can simplify. Define your base colour once, and let a Style Dictionary function generate the ramp based on configuration:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
        <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Then configure your transform in your Style Dictionary setup:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// config.js</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">web</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transforms</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'generateColorRamp'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token literal-property property">transformConfig</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">generateColorRamp</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">lime</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token literal-property property">lightnessShift</span><span class="token operator">:</span> <span class="token number">0.08</span><span class="token punctuation">,</span>
              <span class="token literal-property property">steps</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The transform reads this configuration and generates the ramp:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// transforms/generateColorRamp.js</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'generateColorRamp'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">match</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> config <span class="token operator">=</span> platform<span class="token punctuation">.</span>transformConfig<span class="token operator">?.</span>generateColorRamp<span class="token punctuation">;</span>
    <span class="token keyword">return</span> config <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path <span class="token operator">&amp;&amp;</span> <span class="token function">isConfigured</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>path<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token function-variable function">transform</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> config <span class="token operator">=</span> platform<span class="token punctuation">.</span>transformConfig<span class="token punctuation">.</span>generateColorRamp<span class="token punctuation">;</span>
    <span class="token keyword">const</span> <span class="token punctuation">[</span>lightness<span class="token punctuation">,</span> chroma<span class="token punctuation">,</span> hue<span class="token punctuation">]</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">.</span>components<span class="token punctuation">;</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> lightnessShift<span class="token punctuation">,</span> steps <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">getConfigForToken</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>path<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> ramp <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> steps<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> newLightness <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>
        <span class="token number">0</span><span class="token punctuation">,</span>
        Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> lightness <span class="token operator">-</span> lightnessShift <span class="token operator">*</span> <span class="token punctuation">(</span>steps <span class="token operator">/</span> <span class="token number">2</span> <span class="token operator">-</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> stepNumber <span class="token operator">=</span> <span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">100</span><span class="token punctuation">;</span>

      ramp<span class="token punctuation">[</span>stepNumber<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">$type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">$value</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">colorSpace</span><span class="token operator">:</span> <span class="token string">'oklch'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">[</span>newLightness<span class="token punctuation">,</span> chroma<span class="token punctuation">,</span> hue<span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> ramp<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This produces the same result but keeps your tokens clean. No metadata cluttering your source. Configuration lives in your build setup where it belongs.</p>
<p>Pick whichever approach fits your workflow.</p>
<h2 id="2.-generate-accessible-text-colours-automatically" tabindex="-1">2. Generate accessible text colours automatically</h2>
<p>Here's where structured colour really shines for accessibility. Define a background colour once with WCAG requirements, and a transform generates the appropriate text colours automatically.</p>
<h3 id="define-a-background-with-accessibility-metadata" tabindex="-1">Define a background with accessibility metadata</h3>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"surface"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"com.tokens.a11y"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"generateTextColors"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token property">"wcagLevels"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"AA"</span><span class="token punctuation">,</span> <span class="token string">"AAA"</span><span class="token punctuation">]</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The extension tells your build: generate text colours that pass WCAG AA (4.5:1) and AAA (7:1) contrast.</p>
<h3 id="style-dictionary-transform" tabindex="-1">Style Dictionary transform</h3>
<p>A transform reads this and tests both black and white against the background, picking the best match:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// transforms/generateA11yTextColors.js</span>
<span class="token keyword">import</span> Color <span class="token keyword">from</span> <span class="token string">'colorjs.io'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'generateA11yTextColors'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">match</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.tokens.a11y'</span><span class="token punctuation">]</span><span class="token operator">?.</span>generateTextColors<span class="token punctuation">,</span>
  <span class="token function-variable function">transform</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> config <span class="token operator">=</span> token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.tokens.a11y'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> bgColor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span>
      token<span class="token punctuation">.</span>$value<span class="token punctuation">.</span>hex <span class="token operator">||</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">.</span>colorSpace<span class="token punctuation">,</span>
      token<span class="token punctuation">.</span>$value<span class="token punctuation">.</span>components
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> black <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span><span class="token string">'#000000'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> white <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span><span class="token string">'#ffffff'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> contrastBlack <span class="token operator">=</span> bgColor<span class="token punctuation">.</span><span class="token function">contrast</span><span class="token punctuation">(</span>black<span class="token punctuation">,</span> <span class="token string">'WCAG21'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> contrastWhite <span class="token operator">=</span> bgColor<span class="token punctuation">.</span><span class="token function">contrast</span><span class="token punctuation">(</span>white<span class="token punctuation">,</span> <span class="token string">'WCAG21'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> bestColor <span class="token operator">=</span> contrastWhite <span class="token operator">></span> contrastBlack <span class="token operator">?</span> white <span class="token operator">:</span> black<span class="token punctuation">;</span>
    <span class="token keyword">const</span> bestContrast <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>contrastBlack<span class="token punctuation">,</span> contrastWhite<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token comment">// Generate for each WCAG level requested</span>
    config<span class="token punctuation">.</span>wcagLevels<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">level</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> levelKey <span class="token operator">=</span> level<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> requiredContrast <span class="token operator">=</span> level <span class="token operator">===</span> <span class="token string">'AAA'</span> <span class="token operator">?</span> <span class="token number">7</span> <span class="token operator">:</span> <span class="token number">4.5</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> passes <span class="token operator">=</span> bestContrast <span class="token operator">>=</span> requiredContrast<span class="token punctuation">;</span>

      result<span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">text-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>levelKey<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">$type</span><span class="token operator">:</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">$value</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">colorSpace</span><span class="token operator">:</span> <span class="token string">'srgb'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">hex</span><span class="token operator">:</span> bestColor<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'hex'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">$description</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Text colour for WCAG </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>level<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> on this surface (</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>bestContrast<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 contrast)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> result<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This generates tokens like:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"surface"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token comment">/* ...original background... */</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text-aa"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text colour for WCAG AA on this surface (18.5:1 contrast)"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text-aaa"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text colour for WCAG AAA on this surface (18.5:1 contrast)"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Now when you add a new background colour, accessible text colours are generated automatically. Test against real contrast requirements. Report which ones pass or fail. No manual checking.</p>
<h3 id="validate-at-build-time" tabindex="-1">Validate at build time</h3>
<p>Extend the transform to warn if a pairing fails:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>passes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">⚠️  surface.default text-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>levelKey<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>bestContrast<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 </span><span class="token template-punctuation string">`</span></span> <span class="token operator">+</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">does not meet WCAG </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>level<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> (requires </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>requiredContrast<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1)</span><span class="token template-punctuation string">`</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Catch accessibility regressions during build, not in user testing.</p>
<h2 id="3.-better-conversion-pipelines" tabindex="-1">3. Better conversion pipelines</h2>
<p>A spec-based colour system also makes conversion easier between tools and platforms.</p>
<p>You define your colour once in OKLCH, and your build outputs it in every format your teams need:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Your Style Dictionary (or similar tool) outputs this as:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// For legacy CSS and design tools</span>
<span class="token operator">--</span>color<span class="token operator">-</span>brand<span class="token operator">-</span>primary<span class="token operator">:</span> #bada55<span class="token punctuation">;</span>
<span class="token operator">--</span>color<span class="token operator">-</span>brand<span class="token operator">-</span>primary<span class="token operator">-</span>rgb<span class="token operator">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span><span class="token number">186</span><span class="token punctuation">,</span> <span class="token number">218</span><span class="token punctuation">,</span> <span class="token number">85</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// For modern CSS</span>
<span class="token operator">--</span>color<span class="token operator">-</span>brand<span class="token operator">-</span>primary<span class="token operator">-</span>oklch<span class="token operator">:</span> <span class="token function">oklch</span><span class="token punctuation">(</span><span class="token number">0.77</span> <span class="token number">0.18</span> <span class="token number">117</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// For iOS</span>
<span class="token function">UIColor</span><span class="token punctuation">(</span>red<span class="token operator">:</span> <span class="token number">0.73</span><span class="token punctuation">,</span> <span class="token literal-property property">green</span><span class="token operator">:</span> <span class="token number">0.86</span><span class="token punctuation">,</span> <span class="token literal-property property">blue</span><span class="token operator">:</span> <span class="token number">0.33</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">1.0</span><span class="token punctuation">)</span>

<span class="token comment">// For Android</span>
#badass55

<span class="token comment">// For Design Systems</span>
<span class="token punctuation">{</span>
  <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Brand Primary"</span><span class="token punctuation">,</span>
  <span class="token string-property property">"value"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span> <span class="token string-property property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>One source token. Infinite outputs. Your design tokens become the single source of truth, and every platform consumes what it needs.</p>
<h2 id="tracking-conversions-with-extensions" tabindex="-1">Tracking conversions with extensions</h2>
<p>When you migrate from hex to structured colour (or convert between colour spaces), you might want to keep audit metadata. That's what <code>$extensions</code> is for. Store the original hex value, when you converted it, which tool did the conversion, and the tool version.</p>
<h3 id="example" tabindex="-1">Example</h3>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"colorSpace"</span><span class="token operator">:</span> <span class="token string">"oklch"</span><span class="token punctuation">,</span>
          <span class="token property">"components"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.77</span><span class="token punctuation">,</span> <span class="token number">0.18</span><span class="token punctuation">,</span> <span class="token number">117</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"hex"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.your-tool.converter"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"originalValue"</span><span class="token operator">:</span> <span class="token string">"#bada55"</span><span class="token punctuation">,</span>
              <span class="token property">"convertedAt"</span><span class="token operator">:</span> <span class="token string">"2026-06-23T12:00:00Z"</span><span class="token punctuation">,</span>
              <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0.0"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This saves you if you ever need to debug a conversion, audit where values came from, or reverse a transformation.</p>
<h2 id="making-colour-a-workflow-cornerstone" tabindex="-1">Making colour a workflow cornerstone</h2>
<p>Structured colour is where your token system stops being a collection of hex dumps and starts being a <em>system</em>.</p>
<p>You author in spaces designed for how humans perceive colour. Your tools generate variants, handle conversions, and preserve intent. You scale from one brand colour to hundreds of tokens without hand-picking every shade.</p>
<p>You don't have to migrate everything overnight. Start with OKLCH for new ramps. Keep hex as a fallback for tools that need it. Build your conversion pipeline. Gradually your token structure becomes the source of truth, not the hex values.</p>
<p>By the time you move to the next section of this series, semantic naming, component relationships, or build-time automation, your colour system will be ready to support it. That's the real win.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>From Proposal to Release: Designing Your Design System Workflow</title>
      <link href="https://www.alwaystwisted.com/articles/from-proposal-to-release-designing-your-design-system-workflow.html"/>
      <updated>2026-06-17T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/from-proposal-to-release-designing-your-design-system-workflow.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="the-cost-of-chaos" tabindex="-1">The Cost of Chaos</h2>
<p>It's 10:47 AM on a Tuesday. Courtney, a product designer, has just finished a beautiful new progress bar component for the onboarding flow. They post it in Slack: &quot;New progress bar variant ready - where should this go?&quot;</p>
<p>Silence.</p>
<p>Meanwhile, three channels over, Eddie from engineering has already built their
own version of the same progress bar. It's in production. Nobody told Courtney.
Nobody told Eddie about Courtney. This actually happens. Every week, probably.
If you work in and around a design system, you've definitely lived through this.</p>
<p>In a couple of weeks time, when Jerry (one of the product owners) gets back from their all inclusive holiday, there are three progress bar variants in their
suite of products, each slightly different, one rudimentarily documented, and all causing
confusion.</p>
<p>This isn't a failure of talent or tools. It's a failure of workflow.</p>
<p>This scenario probably happens every week in design systems without clear workflows. Teams spend up to 25% of their time searching for information, recreating work that already exists, or waiting for answers that never come. According to <a href="https://diginomica.com/digital-overload-paradox-teams-drowning-information-starving-insights">Atlassian's State of Teams Report</a>, workers waste a quarter of their workweek just searching for answers, with <a href="https://air.inc/resources/creative-teams-wasting-time-searching-for-files">creative teams</a> particularly affected.</p>
<p>But the financial cost is just the beginning. There's a human cost, and that's
the part that is rarely talked about. Designers stop proposing ideas because they don't
know how to contribute. Engineers lose trust in the design system and build
their own solutions. Stakeholders watch the system fragment and question its
value. Morale suffers because people feel like they're working against the
system, not with it. That's exhausting.</p>
<p>A design system without clear workflows is just a collection of components and
colours gathering dust and breeding confusion.</p>
<h2 id="why-workflows-matter%3A-beyond-just-getting-things-done" tabindex="-1">Why Workflows Matter: Beyond Just Getting Things Done</h2>
<p>Most people think about design systems and imagine components. Shiny things. Documentation. The visible stuff. But that's not actually the foundation. The process is. The process is what makes the shiny stuff actually useful.</p>
<p>A workflow is how the intent becomes the reality. It's the mechanisms that turn
an idea into something shipped that products actually use. Without clarity around
how the work flows through the system, friction can accumulate everywhere.</p>
<h3 id="when-workflows-are-unclear" tabindex="-1">When Workflows Are Unclear</h3>
<p>When workflows are unclear, duplicated work becomes inevitable. Three versions of progress bar. Two of button. And nobody knows which one to actually use, so they build another one. This is where most teams start bleeding.</p>
<p>Quality becomes inconsistent. Some components get thorough design and testing. Others ship half-done without docs. Trust erodes. Users stop believing the system will solve their problem.</p>
<p>Decision-making becomes glacially slow. Proposals sit for weeks. A designer proposes Button variants on Monday, gets no response, and by the next week has given up and built their own. Teams stop proposing improvements. The system stagnates.</p>
<p>Adoption plummets because nobody understands what exists. Or how to use it. Why gamble on an unclear component when building it themselves is faster?</p>
<p>The core team burns out answering the same questions over and over. Explaining decisions nobody wrote down. Debugging variants nobody knew existed. The team feels reactive instead of generative. The design system becomes a gatekeeper. It makes work harder, not easier.</p>
<h3 id="when-workflows-are-clear" tabindex="-1">When Workflows Are Clear</h3>
<p>Now imagine the opposite.</p>
<p>A project needs a new component. The team knows what to do: submit an RFC, post it in the right channel, get reviewed within a couple of weeks, receive a documented decision, then move through design, handoff, development, testing, documentation, and release. All predictable.</p>
<p>This is the power of clarity. Friction decreases because everyone knows what comes next. Time spent creating increases.</p>
<p>Decisions happen faster because the criteria are clear and people are aligned. A junior designer proposes ideas without asking permission first. They know how feedback arrives. What happens next. Why. The process is transparent. No hidden gatekeeping.</p>
<p>Planning becomes possible. &quot;We need Button variants by Q3.&quot; &quot;That's an 8-10 week timeline. Yes, we can do it.&quot; Teams can commit instead of guessing.</p>
<p>Adoption grows because products understand what exists and can rely on its quality. The system becomes faster than building their own. The core team stops fighting fires. Contributors feel heard. Teams feel trusted to make decisions. These outcomes aren't incidental. They directly impact business: faster time to market, higher quality, lower turnover, stronger collaboration.</p>
<h2 id="the-organisational-impact-of-workflows" tabindex="-1">The Organisational Impact of Workflows</h2>
<p>Clear workflows affect organisational dynamics in ways that go beyond the design system itself.</p>
<h3 id="onboarding" tabindex="-1">Onboarding</h3>
<p>New team members learn the system by doing it. If the process is documented and clear, they're productive in weeks.</p>
<p>They can read how to contribute. See recent decisions and understand the reasoning. See what components exist and why. If the process is informal and unwritten? New people are lost for months. Constantly asking questions. Slowing down the whole team because they're always blocked.</p>
<h3 id="cross-team-collaboration" tabindex="-1">Cross-team Collaboration</h3>
<p>When product teams understand how to propose and contribute, the design system becomes a shared resource instead of something a gatekeeper controls. Teams don't wait for the design system team to build what they need. They propose it, collaborate on it, and help build it. Ownership shifts from &quot;the design system team builds things&quot; to &quot;we all build the system together.&quot;</p>
<h3 id="scalability" tabindex="-1">Scalability</h3>
<p>At 5 people, informal works. Everyone knows everyone. Communication happens naturally. At 50 people across multiple teams, informal breaks. People miss announcements. Decisions made in one team aren't known in another. Information gets lost. Clear processes let you grow without chaos because the process scales. You don't have to retrain everyone individually. You point them to the documented process.</p>
<h3 id="stakeholder-trust" tabindex="-1">Stakeholder Trust</h3>
<p>Executives see predictable releases. They see documented decisions. They see growing adoption. They see that the system is actually being used and improving. They're more likely to invest in the system, allocate budget, and support its growth. Without this visibility, stakeholders lose confidence. &quot;We built a design system but nobody's using it. Is it worth keeping?&quot;</p>
<h3 id="risk-mitigation" tabindex="-1">Risk Mitigation</h3>
<p>When processes are clear and decisions are recorded, you avoid surprises months
later. You can explain why the <code>&lt;video-card&gt;</code> was deprecated. You can show that products
had adequate notice to migrate. You can demonstrate that decisions were made
thoughtfully. When things go wrong (and they will) you have a record of why. This
reduces liability around breaking changes and protects the organisation.</p>
<h2 id="the-six-pillars%3A-what-each-one-enables" tabindex="-1">The Six Pillars: What Each One Enables</h2>
<p>A healthy design system workflow has six interconnected foundations:
Contribution, Review and Approval, Documentation, Communication, Iteration, and
Versioning and Deprecation. None of these are revolutionary. None are complex.
You're not building rocket ships here. You're creating clarity around how work
moves through the system. Honestly, it's almost boring how simple this is once
you see it.</p>
<h3 id="contribution%3A-making-it-safe-to-propose" tabindex="-1">Contribution: Making It Safe to Propose</h3>
<p>How do people even know they can propose something? That's the first pillar. Clarity about how new work enters the system.</p>
<p>Without it, only the confident people propose. Everyone else? They keep their ideas to themselves. The system stagnates because you're only getting input from people who are already sure they're allowed to speak up. Which is a shame. The best ideas often come from junior designers or engineers in product teams who actually use the system. But they'll never say anything if the door isn't obvious.</p>
<p>When contribution is clear, something shifts. A designer with an idea thinks, &quot;I have a new pattern. I'm not sure if it belongs, but I know exactly who to ask and how to ask it.&quot;</p>
<p>Ideas surface. The team evaluates them on merit, not on how confident the proposer is. Junior designers contribute. Engineers from product teams spot patterns that the core team missed. The system breathes.</p>
<h3 id="review-and-approval%3A-making-decisions-matter" tabindex="-1">Review and Approval: Making Decisions Matter</h3>
<p>The second pillar is what happens when someone actually proposes something. A clear process for deciding what gets built.</p>
<p>Without it, decisions are inconsistent and slow. Someone proposes a Button variant. Weeks pass. Then quietly it gets approved or rejected without explanation. Another proposal gets a quick yes. Nobody knows why. Decision-makers aren't aligned on what matters, so each one evaluates proposals differently. I've watched this paralyze teams.</p>
<p>Clear review processes change this. Decisions still require thought, but they happen predictably. A proposal gets reviewed on Tuesday. Thursday, the team has a decision and a documented reason.</p>
<p>That reason isn't &quot;I didn't like it.&quot; It's something concrete: &quot;This solves a problem three teams have but it overlaps with an existing pattern, so we're recommending you combine them.&quot; Products understand decisions. They trust them.</p>
<h3 id="documentation%3A-making-knowledge-stick" tabindex="-1">Documentation: Making Knowledge Stick</h3>
<p>Capturing the reasoning and the how-to. That's the third pillar. Why does a component exist the way it does? How do you use it?</p>
<p>Without documentation, knowledge lives in people's heads. A designer knows the constraints of Button because they built it. When they leave, the team loses that knowledge. New people discover things accidentally. Decisions get remade. Over and over. Because nobody wrote anything down.</p>
<p>Clear documentation means that knowledge compounds instead of evaporating. A product team new to the system can understand a component without asking anyone. They know what it's for. How to use it. What its constraints are. How it relates to other components.</p>
<p>The system becomes smarter over time because improvements and learnings are recorded. When someone thinks &quot;Button doesn't work for this use case,&quot; they can read the documentation and understand why it was designed that way. Or see that it's a legitimate gap and propose an improvement.</p>
<h3 id="communication%3A-keeping-everyone-aligned" tabindex="-1">Communication: Keeping Everyone Aligned</h3>
<p>How does information actually reach people? That's the fourth pillar. Regular rituals and channels. Not suggestions. Rituals.</p>
<p>Without them, important discussions happen in DMs and Slack threads and vanish. One team makes a decision that affects another team, but they never find out. People work in isolation. Questions go unanswered because someone assumed someone else answered them. This is where things fall apart quietly.</p>
<p>Clear communication means information flows. Weekly syncs happen at the same time every week, so people know when to pay attention.</p>
<p>Decisions go into a shared log so they're findable. Proposals get posted in one place so people know where to look. When someone asks a question, they know where to ask it and they'll get an answer. The team moves together instead of in separate directions.</p>
<h3 id="iteration%3A-making-the-system-evolve" tabindex="-1">Iteration: Making the System Evolve</h3>
<p>Here's the fifth pillar: what happens after you ship? A clear way to improve things once they're in the wild.</p>
<p>Without it, components ship and become frozen. User feedback arrives but goes nowhere. Bugs are reported but never fixed. The system becomes worse over time. The gap between what users need and what exists just keeps growing. I've seen this destroy otherwise good work.</p>
<p>Iteration mechanisms mean the system keeps getting better. A product team finds a bug in Button. They know how to report it. They know it'll be reviewed. They know they'll see it fixed in the next release. The system feels alive. Users feel heard. Improvements compound.</p>
<h3 id="versioning-and-deprecation%3A-managing-change" tabindex="-1">Versioning and Deprecation: Managing Change</h3>
<p>The last one is about change itself. How do things change? Clear rules for how it happens and when products need to adapt.</p>
<p>Without it, breaking changes break things without warning. A component's API changes and suddenly products break. Nobody told them. The design system becomes unreliable. Teams stop trusting it. And honestly, who could blame them?</p>
<p>Clear versioning means change is predictable. When Button's API changes, products know it's coming. They have time to plan the migration. They have a clear guide on how to do it. They have support from the team. Change is still work, but it's not chaos.</p>
<p>Together, these six pillars create a system where ideas surface safely, decisions matter, knowledge accumulates, communication flows, improvement happens, and change is manageable. That's the foundation of a design system people actually trust and use.</p>
<h2 id="the-journey%3A-from-idea-to-shipped-component" tabindex="-1">The Journey: From Idea to Shipped Component</h2>
<p>Every component follows a consistent path through the system. Here's what a well-structured contribution journey looks like:</p>
<pre><code>Ideation &gt; Validation &gt; Design &gt; Review &gt; Development &gt; Testing &gt; Documentation &gt; Release &gt; Feedback
</code></pre>
<h3 id="ideation" tabindex="-1">Ideation</h3>
<p>Someone notices a pattern being built repeatedly. &quot;We're rebuilding progress bars in three different ways across our products.&quot; That observation becomes the seed for a new component.</p>
<h3 id="validation" tabindex="-1">Validation</h3>
<p>Before investing in design and development, the proposer does some quick research. Does this pattern already exist in the system? Has someone already tried to solve this? Is this solving a real problem that multiple teams face, or is it just one team's edge case? This phase is short, maybe a day or two, but it prevents duplicated effort.</p>
<h3 id="design" tabindex="-1">Design</h3>
<p>The component gets designed with all its variants and edge cases mapped out. Hover states, error states, loading states, disabled states, different content lengths. The design gets explicit about constraints: when you should use this component and when you shouldn't.</p>
<h3 id="review" tabindex="-1">Review</h3>
<p>This is the decision point. The team looks at the design and asks: is this right for the system? Does it fit with our patterns? Does it solve a problem in a way that's aligned with our philosophy? The review takes time, but it's focused time. The team has a decision-making framework. Within two weeks, the proposer knows the outcome.</p>
<h3 id="development" tabindex="-1">Development</h3>
<p>If the review is approved, engineering builds the component. They integrate it with the system's infrastructure, ensure it works in all the browsers the system supports, and write the code in a way that's maintainable and consistent with existing components.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Don't throw designs over the wall.</strong> During development, engineers often discover constraints or possibilities the design completely missed. The best components come from continued conversation between designer and engineer. Not handoff. Conversation. Build in time for the developer to ask questions, push back, suggest adjustments. Collaborate. It'll be stronger because of it.</p>
</div></div>
<h3 id="testing" tabindex="-1">Testing</h3>
<p>Quality assurance covers browsers, devices, and, critically, accessibility.
Testing happens in parallel (as the developer builds it) and after development. A component that doesn't
work for people using screen readers or keyboard navigation isn't ready. Testing
is thorough.</p>
<h3 id="documentation" tabindex="-1">Documentation</h3>
<p>Not as an afterthought, but as part of the shipping process. Usage guidelines explain what the component is for. Real code examples show how to use it. Accessibility notes highlight important considerations. Edge case documentation explains what happens in unusual situations and when you should reach for a different component instead.</p>
<h3 id="release" tabindex="-1">Release</h3>
<p>The component ships in a new version of the design system. It gets announced. Teams know it's available. If they have questions, there's a clear place to ask. The release process is predictable, maybe &quot;always the third Thursday&quot;, so products can plan their updates.</p>
<h3 id="feedback" tabindex="-1">Feedback</h3>
<p>As products use the component, usage gets monitored. Bugs are reported. Enhancement requests come in. Improvements are tracked. The component doesn't become frozen after release. It evolves based on real-world use.</p>
<p>The timeline varies depending on the component's complexity. Simple components, like a new colour or a minor variant of an existing pattern, might complete this journey in 1-2 weeks. Medium-complexity components take 4-6 weeks. Complex ones with multiple states and accessibility considerations take 8-12 weeks.</p>
<p>But the phases stay consistent. Everyone knows what comes next. A product team proposing a new component understands the timeline: &quot;We need Button variants by Q3.&quot; &quot;That's 4-6 weeks. We can fit that in before release.&quot; It becomes predictable, which means it becomes plannable.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>Not all of these phases need to happen in order, one after the other. Depending on your team's size and structure, some can and should happen in parallel. Design and development can run together. Testing can start mid-development. Documentation can be drafted during design. Talk with your team about what actually works for them. A three-person team will move differently than a thirty-person team. Build a process that matches your reality, not an imaginary ideal.</p>
</div></div>
<h2 id="the-reality" tabindex="-1">The Reality</h2>
<p>Without clear workflows, your design system becomes a liability. Variants multiply. People stop proposing and start building their own. The core team burns out. Recovery takes starting over.</p>
<p>With clear workflows, the system becomes something teams actually trust. Contributions flow. Decisions happen. Teams depend on it. Adoption grows.</p>
<p>That's it. The difference is process clarity. Nothing else.</p>
<h2 id="start-with-understanding" tabindex="-1">Start With Understanding</h2>
<p>Before you build anything, understand where you actually are. (Don't skip this part.)</p>
<p>Spend 30 minutes this week mapping your current workflow. Pick a recent component that shipped and trace it:</p>
<ul>
<li>Where did the idea come from?</li>
<li>Who decided it was worth building?</li>
<li>How did it get handed off to engineering?</li>
<li>How long did each phase actually take?</li>
</ul>
<p>Then ask your team where the friction is. Where do people spend time navigating process instead of doing work? Where does communication break down? Where did that last component get stuck?</p>
<p>That friction point is your signal. That's where a clear workflow creates the most value.</p>
<p>Your workflow doesn't have to be perfect. It doesn't have to win awards. I've seen perfect workflows that nobody follows because they're overcomplicated. What matters is that it's clear, documented, and actually applied consistently. That's really it.</p>
<p>That's enough.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 16) - Automating Colour Contrast With Design Tokens</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-16.html"/>
      <updated>2026-06-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-16.html</id>
      <content type="html">
        <![CDATA[
        <p>In earlier articles of this series, we've explored how to structure, transform, and layer design tokens. One practical challenge that emerges when building design systems is ensuring accessible colour combinations at scale. Manually checking contrast ratios for dozens of colour tokens quickly becomes impractical, and accessibility issues typically surface during audits or, worse, when users report readability problems.</p>
<p>Build-time automation solves this. Using Style Dictionary and a colour contrast library, we can generate accessible text colour pairs for every background token and validate them against WCAG standards.</p>
<h2 id="setting-up-token-structure" tabindex="-1">Setting Up Token Structure</h2>
<p>The foundation of this system is a naming convention that makes relationships
explicit. When you see <code>button-primary-background</code>, you should immediately know
there's an optional corresponding <code>button-primary-foreground</code> token for defined
foreground (text) colours.</p>
<h3 id="semantic-colour-tokens" tabindex="-1">Semantic Colour Tokens</h3>
<p>Let's start with the semantic colour palette: foundational brand and neutral colours that all component tokens reference.</p>
<pre class="language-json"><code class="language-json"><span class="token comment">// tokens/color/semantic.json</span>
<span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#407ac2"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Primary brand color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#e862e5"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Secondary accent color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"neutral"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"white"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#ffffff"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"black"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#1a1a1a"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"grey"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"50"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#f9fafb"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#f3f4f6"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#e5e7eb"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#374151"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"900"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#111827"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="component-tokens-with-naming-convention" tabindex="-1">Component Tokens with Naming Convention</h3>
<p>Now create component tokens with backgrounds. The system will automatically generate three text colour tokens in your CSS output:</p>
<ul>
<li><code>{component}-{variant}-background</code> - your input background token</li>
<li><code>{component}-{variant}-foreground-aa</code> - auto-generated colour guaranteed to pass WCAG AA (4.5:1)</li>
<li><code>{component}-{variant}-foreground-aaa</code> - auto-generated colour targeting WCAG AAA (7:1)</li>
<li><code>{component}-{variant}-foreground</code> - only appears if you define a foreground token with your chosen text colour (optional)</li>
</ul>
<pre class="language-json"><code class="language-json"><span class="token comment">// tokens/color/component.json</span>
<span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Primary button background"</span>
      <span class="token punctuation">}</span>
      <span class="token comment">// foreground-aa and foreground-aaa will be auto-generated</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"danger"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#dc2626"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"surface"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.neutral.white}"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"elevated"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.neutral.grey.50}"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.neutral.white}"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Default page background"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The naming convention is crucial: by ending tokens with <code>-background</code>, we create a clear signal for our transform to generate corresponding <code>-foreground-aa</code> and <code>-foreground-aaa</code> tokens.</p>
<h2 id="chosen-foreground-colour-(optional)" tabindex="-1">Chosen Foreground Colour (Optional)</h2>
<p>You're not limited to black and white. If a specific colour has been decided for
a background define it as a <code>foreground</code> property. The system will generate this too.</p>
<p>The system will always generate AA and AAA foreground (text) colours (either black or white). If you've defined a foreground colour it will test the contrast against the background. It will then add a report of what passed and hasn't passed on the command line to quickly review, and it will generate CSS custom properties with the AA, AAA and your defined values with added comments showing the colour contrast result.</p>
<p>Validation runs during the build and reports what it finds. Auto-generated AA
combinations always pass since they're chosen from black or white. Warnings
surface when AAA isn't met or your chosen foreground fails AA, giving you the
visibility needed to make informed decisions.</p>
<h3 id="default-token-names" tabindex="-1">Default Token Names</h3>
<p>By default, the system looks for <code>background</code> and <code>foreground</code> properties:</p>
<pre class="language-json"><code class="language-json"><span class="token comment">// tokens/color/component.json</span>
<span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#407ac2"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Primary button background"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"foreground"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#ffffff"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"White chosen by design team"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#faf5ff"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
      <span class="token comment">// No foreground = only auto-generated text-aa and text-aaa</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="customisable-token-names" tabindex="-1">Customisable Token Names</h3>
<p>You can customise which token properties the system looks for. This is useful if your design system already has different naming conventions.</p>
<p>Configure token names in your build script:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// build-tokens.js</span>
<span class="token keyword">const</span> contrastConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">backgroundTokenName</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token comment">// Change to 'bg', 'surface', 'pane', etc.</span>
  <span class="token literal-property property">foregroundTokenName</span><span class="token operator">:</span> <span class="token string">'foreground'</span><span class="token punctuation">,</span> <span class="token comment">// Change to 'text', 'color', 'ink', etc.</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Example: Using <code>bg</code> and <code>text</code> instead:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> contrastConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">backgroundTokenName</span><span class="token operator">:</span> <span class="token string">'bg'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">foregroundTokenName</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Then in your tokens:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"bg"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#407ac2"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#ffffff"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The system will automatically adapt to use your chosen names.</p>
<h2 id="installing-dependencies" tabindex="-1">Installing Dependencies</h2>
<p>As well as Style Dictionary we'll also use <a href="https://colorjs.io">colorjs.io</a> for colour contrast calculations.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save-dev style-dictionary colorjs.io</code></pre>
<h2 id="creating-the-contrast-transform" tabindex="-1">Creating the Contrast Transform</h2>
<p>This is where the magic happens. We'll create a Style Dictionary transform that finds all tokens ending in <code>-background</code>, calculates which text colour has the best contrast, and adds metadata to generate new tokens.</p>
<h3 id="the-contrast-calculation-helper" tabindex="-1">The Contrast Calculation Helper</h3>
<p>We need three helper functions to handle the heavy lifting. The first calculates the contrast ratio between two colours. It takes two colour values and returns a ratio between 1 and 21. If anything goes wrong with the calculation, it logs an error and returns 0.</p>
<p>The second function is an algorithm that finds the best contrasting colour from any list of options. It iterates through each option, calculates the contrast ratio against the background, and returns the one with the highest ratio along with whether it passes the minimum threshold.</p>
<p>The third function returns the specific list of fallback colours: pure white and pure black. These are always tested. This list is passed to the second function to find the best automatic contrast. When a chosen foreground token is defined, it's tested separately in the transform against the same AA and AAA thresholds.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// lib/contrast-helpers.js</span>
<span class="token keyword">import</span> Color <span class="token keyword">from</span> <span class="token string">'colorjs.io'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getContrastRatio</span><span class="token punctuation">(</span><span class="token parameter">color1<span class="token punctuation">,</span> color2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> c1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span>color1<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> c2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Color</span><span class="token punctuation">(</span>color2<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> Math<span class="token punctuation">.</span><span class="token function">abs</span><span class="token punctuation">(</span>c1<span class="token punctuation">.</span><span class="token function">contrast</span><span class="token punctuation">(</span>c2<span class="token punctuation">,</span> <span class="token string">'WCAG21'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error calculating contrast between </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>color1<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> and </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>color2<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      error
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">findBestContrast</span><span class="token punctuation">(</span>
  <span class="token parameter">backgroundColor<span class="token punctuation">,</span>
  foregroundOptions<span class="token punctuation">,</span>
  minRatio <span class="token operator">=</span> <span class="token number">4.5</span></span>
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> bestColor <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> bestRatio <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> fgColor <span class="token keyword">of</span> foregroundOptions<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> ratio <span class="token operator">=</span> <span class="token function">getContrastRatio</span><span class="token punctuation">(</span>backgroundColor<span class="token punctuation">,</span> fgColor<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>ratio <span class="token operator">></span> bestRatio<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      bestColor <span class="token operator">=</span> fgColor<span class="token punctuation">;</span>
      bestRatio <span class="token operator">=</span> ratio<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">color</span><span class="token operator">:</span> bestColor<span class="token punctuation">,</span>
    <span class="token literal-property property">ratio</span><span class="token operator">:</span> bestRatio<span class="token punctuation">,</span>
    <span class="token literal-property property">passes</span><span class="token operator">:</span> bestRatio <span class="token operator">>=</span> minRatio<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getDefaultForegroundOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">'#ffffff'</span><span class="token punctuation">,</span> <span class="token string">'#000000'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="the-transform" tabindex="-1">The Transform</h3>
<p>The transform filters for tokens matching your configured background property name, retrieves any chosen foreground colour, calculates contrast ratios, and packages the results into metadata attached to each token.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// lib/transforms/contrast.js</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  getContrastRatio<span class="token punctuation">,</span>
  findBestContrast<span class="token punctuation">,</span>
  getDefaultForegroundOptions<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'../contrast-helpers.js'</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">createContrastTransform</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'color/add-contrast'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'attribute'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">(</span>
        token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'color'</span> <span class="token operator">&amp;&amp;</span>
        token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> config<span class="token punctuation">.</span>backgroundTokenName
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">transform</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> backgroundColor <span class="token operator">=</span> token<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
      <span class="token keyword">const</span> componentGroup <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> componentVariant <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

      <span class="token keyword">const</span> chosenForeground <span class="token operator">=</span>
        options<span class="token punctuation">.</span>dictionary<span class="token punctuation">.</span>tokens<span class="token operator">?.</span><span class="token punctuation">[</span>componentGroup<span class="token punctuation">]</span><span class="token operator">?.</span><span class="token punctuation">[</span>componentVariant<span class="token punctuation">]</span><span class="token operator">?.</span><span class="token punctuation">[</span>
          config<span class="token punctuation">.</span>foregroundTokenName
        <span class="token punctuation">]</span><span class="token operator">?.</span>value<span class="token punctuation">;</span>

      <span class="token keyword">const</span> defaultOptions <span class="token operator">=</span> <span class="token function">getDefaultForegroundOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> aa <span class="token operator">=</span> <span class="token function">findBestContrast</span><span class="token punctuation">(</span>backgroundColor<span class="token punctuation">,</span> defaultOptions<span class="token punctuation">,</span> <span class="token number">4.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> aaa <span class="token operator">=</span> <span class="token function">findBestContrast</span><span class="token punctuation">(</span>backgroundColor<span class="token punctuation">,</span> defaultOptions<span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token keyword">let</span> chosenForegroundInfo <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>chosenForeground<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> chosenAARatio <span class="token operator">=</span> <span class="token function">getContrastRatio</span><span class="token punctuation">(</span>
          backgroundColor<span class="token punctuation">,</span>
          chosenForeground
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> chosenAAARatio <span class="token operator">=</span> <span class="token function">getContrastRatio</span><span class="token punctuation">(</span>
          backgroundColor<span class="token punctuation">,</span>
          chosenForeground
        <span class="token punctuation">)</span><span class="token punctuation">;</span>

        chosenForegroundInfo <span class="token operator">=</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">color</span><span class="token operator">:</span> chosenForeground<span class="token punctuation">,</span>
          <span class="token literal-property property">ratioAA</span><span class="token operator">:</span> chosenAARatio<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">ratioAAA</span><span class="token operator">:</span> chosenAAARatio<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">passesAA</span><span class="token operator">:</span> chosenAARatio <span class="token operator">>=</span> <span class="token number">4.5</span><span class="token punctuation">,</span>
          <span class="token literal-property property">passesAAA</span><span class="token operator">:</span> chosenAAARatio <span class="token operator">>=</span> <span class="token number">7</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>

      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        <span class="token operator">...</span>token<span class="token punctuation">.</span>attributes<span class="token punctuation">,</span>
        <span class="token literal-property property">contrast</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">aa</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">color</span><span class="token operator">:</span> aa<span class="token punctuation">.</span>color<span class="token punctuation">,</span>
            <span class="token literal-property property">ratio</span><span class="token operator">:</span> aa<span class="token punctuation">.</span>ratio<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token literal-property property">passes</span><span class="token operator">:</span> aa<span class="token punctuation">.</span>passes<span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token literal-property property">aaa</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">color</span><span class="token operator">:</span> aaa<span class="token punctuation">.</span>color<span class="token punctuation">,</span>
            <span class="token literal-property property">ratio</span><span class="token operator">:</span> aaa<span class="token punctuation">.</span>ratio<span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token literal-property property">passes</span><span class="token operator">:</span> aaa<span class="token punctuation">.</span>passes<span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token literal-property property">chosen</span><span class="token operator">:</span> chosenForegroundInfo<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The transform accepts a config object containing <code>backgroundTokenName</code> and <code>foregroundTokenName</code>, making it adaptable to any naming convention. For each matching background token, it computes AA and AAA compliance using black and white as fallback options, ensuring a guaranteed accessible baseline regardless of your chosen naming. It tests any chosen foreground colour against the same thresholds. All this metadata (colours, ratios, and compliance flags) is stored as part of the token's attributes, making it immediately available to downstream formatting and validation.</p>
<h2 id="creating-output-formats" tabindex="-1">Creating Output Formats</h2>
<p>Now we need to generate the actual token files as CSS custom properties.</p>
<h3 id="css-format-with-auto-generated-text-tokens" tabindex="-1">CSS Format with Auto-Generated Text Tokens</h3>
<p>The CSS format builds a stylesheet by iterating through all tokens. For each token with contrast metadata, it outputs the original background token, then the AA and AAA text colours. If a foreground colour was chosen, it outputs that too with a compliance indicator (✅ or ❌). It also adds a warning comment if the auto-generated AAA colour doesn't meet the standard.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// lib/formats/css-with-contrast.js</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">createCssWithContrastFormat</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/variables-with-contrast'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary<span class="token punctuation">,</span> options <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> tokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">;</span>
      <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/**\n'</span><span class="token punctuation">;</span>
      output <span class="token operator">+=</span> <span class="token string">' * Design Tokens with Auto-Generated Contrast Colors\n'</span><span class="token punctuation">;</span>
      output <span class="token operator">+=</span> <span class="token string">' * Generated by Style Dictionary\n'</span><span class="token punctuation">;</span>
      output <span class="token operator">+=</span> <span class="token string">' * DO NOT EDIT DIRECTLY\n'</span><span class="token punctuation">;</span>
      output <span class="token operator">+=</span> <span class="token string">' */\n\n'</span><span class="token punctuation">;</span>
      output <span class="token operator">+=</span> <span class="token string">':root {\n'</span><span class="token punctuation">;</span>

      tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>attributes<span class="token operator">?.</span>contrast<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> baseName <span class="token operator">=</span> token<span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>
            <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>backgroundTokenName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            <span class="token string">''</span>
          <span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> <span class="token punctuation">{</span> aa<span class="token punctuation">,</span> aaa<span class="token punctuation">,</span> chosen <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>contrast<span class="token punctuation">;</span>

          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>foregroundTokenName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-aa: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>aa<span class="token punctuation">.</span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>aa<span class="token punctuation">.</span>ratio<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 */\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>foregroundTokenName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-aaa: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>aaa<span class="token punctuation">.</span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>aaa<span class="token punctuation">.</span>ratio<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 */\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

          <span class="token keyword">if</span> <span class="token punctuation">(</span>chosen<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">const</span> chosenStatus <span class="token operator">=</span> chosen<span class="token punctuation">.</span>passesAA <span class="token operator">?</span> <span class="token string">'✅'</span> <span class="token operator">:</span> <span class="token string">'❌'</span><span class="token punctuation">;</span>
            output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>config<span class="token punctuation">.</span>foregroundTokenName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>chosen<span class="token punctuation">.</span>color<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>chosenStatus<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>chosen<span class="token punctuation">.</span>ratioAA<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 */\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>

          <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>aaa<span class="token punctuation">.</span>passes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  /* ⚠️  AAA not met for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> (requires 7:1) */\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>

          output <span class="token operator">+=</span> <span class="token string">'\n'</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      output <span class="token operator">+=</span> <span class="token string">'}\n'</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> output<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The format uses the config's <code>backgroundTokenName</code> and <code>foregroundTokenName</code> to correctly identify tokens and generate CSS variable names that match your naming convention, regardless of what you named them in your token structure.</p>
<p><strong>Output example:</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Background with chosen foreground (tested and reported) */</span>
  <span class="token property">--button-primary-background</span><span class="token punctuation">:</span> #407ac2<span class="token punctuation">;</span>
  <span class="token property">--button-primary-foreground-aa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 4.78:1 (auto-generated) */</span>
  <span class="token property">--button-primary-foreground-aaa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 4.78:1 (auto-generated) */</span>
  <span class="token property">--button-primary-foreground</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span> <span class="token comment">/* ❌ 4.39:1 (defined value) */</span>
  <span class="token comment">/* ⚠️  AAA not met for button-primary (requires 7:1) */</span>

  <span class="token comment">/* Background without chosen foreground (auto-generated only) */</span>
  <span class="token property">--button-secondary-background</span><span class="token punctuation">:</span> #e862e5<span class="token punctuation">;</span>
  <span class="token property">--button-secondary-foreground-aa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 6.89:1 */</span>
  <span class="token property">--button-secondary-foreground-aaa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 6.89:1 */</span>

  <span class="token comment">/* High contrast background (both auto-generated colors pass AAA) */</span>
  <span class="token property">--surface-default-background</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--surface-default-foreground-aa</span><span class="token punctuation">:</span> #1a1a1a<span class="token punctuation">;</span> <span class="token comment">/* 16.82:1 */</span>
  <span class="token property">--surface-default-foreground-aaa</span><span class="token punctuation">:</span> #1a1a1a<span class="token punctuation">;</span> <span class="token comment">/* 16.82:1 */</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="build-time-validation-and-reporting" tabindex="-1">Build-Time Validation and Reporting</h2>
<p>The validation action runs during the build and generates a report on colour compliance.</p>
<h3 id="validation-action" tabindex="-1">Validation Action</h3>
<p>The validation action iterates through all tokens and generates reports. It categorises tokens into two groups: those where auto-generated colours meet WCAG AA (always the case), and warnings for any chosen foreground colours that don't reach AA or auto-generated colours that don't meet AAA.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// lib/actions/validate-contrast.js</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">createValidateContrastAction</span><span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'validate-contrast'</span><span class="token punctuation">,</span>
    <span class="token function-variable function">do</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">dictionary<span class="token punctuation">,</span> config</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'\n🔍 Validating colour contrast...\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token keyword">const</span> passes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> warnings <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> chosenFails <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

      dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">token</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>attributes<span class="token operator">?.</span>contrast<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> <span class="token punctuation">{</span> aa<span class="token punctuation">,</span> aaa<span class="token punctuation">,</span> chosen <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>attributes<span class="token punctuation">.</span>contrast<span class="token punctuation">;</span>
          <span class="token keyword">const</span> tokenName <span class="token operator">=</span> token<span class="token punctuation">.</span>name<span class="token punctuation">;</span>

          passes<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>tokenName<span class="token punctuation">)</span><span class="token punctuation">;</span>

          <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>aaa<span class="token punctuation">.</span>passes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            warnings<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
              <span class="token literal-property property">token</span><span class="token operator">:</span> tokenName<span class="token punctuation">,</span>
              <span class="token literal-property property">background</span><span class="token operator">:</span> token<span class="token punctuation">.</span>value<span class="token punctuation">,</span>
              <span class="token literal-property property">foreground</span><span class="token operator">:</span> aaa<span class="token punctuation">.</span>color<span class="token punctuation">,</span>
              <span class="token literal-property property">ratio</span><span class="token operator">:</span> aaa<span class="token punctuation">.</span>ratio<span class="token punctuation">,</span>
              <span class="token literal-property property">required</span><span class="token operator">:</span> <span class="token number">7</span><span class="token punctuation">,</span>
              <span class="token literal-property property">level</span><span class="token operator">:</span> <span class="token string">'AAA'</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>

          <span class="token keyword">if</span> <span class="token punctuation">(</span>chosen <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>chosen<span class="token punctuation">.</span>passesAA<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            chosenFails<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
              <span class="token literal-property property">token</span><span class="token operator">:</span> tokenName<span class="token punctuation">,</span>
              <span class="token literal-property property">foreground</span><span class="token operator">:</span> chosen<span class="token punctuation">.</span>color<span class="token punctuation">,</span>
              <span class="token literal-property property">ratio</span><span class="token operator">:</span> chosen<span class="token punctuation">.</span>ratioAA<span class="token punctuation">,</span>
              <span class="token literal-property property">required</span><span class="token operator">:</span> <span class="token number">4.5</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>After categorising all the tokens, it reports the results. Passing tokens get a simple count, warnings are listed with their ratios and requirements, and failures trigger the build to exit with an error.</p>
<pre class="language-javascript"><code class="language-javascript">      <span class="token keyword">if</span> <span class="token punctuation">(</span>passes<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">✅ </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>passes<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> color combinations pass WCAG AA\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>warnings<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">⚠️  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>warnings<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> color combinations don't meet WCAG AAA:\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        warnings<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">w</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>w<span class="token punctuation">.</span>token<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   └─ </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>w<span class="token punctuation">.</span>ratio<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 (requires </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>w<span class="token punctuation">.</span>required<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 for AAA)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>chosenFails<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">⚠️  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>chosenFails<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> chosen foreground colours don't meet WCAG AA:\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        chosenFails<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">f</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>f<span class="token punctuation">.</span>token<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   └─ Chosen: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>f<span class="token punctuation">.</span>foreground<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>f<span class="token punctuation">.</span>ratio<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1 (requires </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>f<span class="token punctuation">.</span>required<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:1)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>

      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'✅ All auto-generated colour combinations meet WCAG AA standards\\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function-variable function">undo</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The validation action runs during the build and reports what it finds. Since the
auto-generated AA and AAA colours are always chosen from black or white, they're
guaranteed to pass AA on any realistic background. Warnings surface when AAA
isn't met or when a chosen foreground colour doesn't reach AA giving
you the visibility without blocking the build.</p>
<h2 id="style-dictionary-configuration" tabindex="-1">Style Dictionary Configuration</h2>
<p>Now let's put it all together. Start by importing all the pieces we've created, then define your configuration object with your chosen token names. Register each custom transform, format, and action with Style Dictionary. Then configure the build with your token sources and platforms. The CSS platform includes our custom transform in the transforms array and our custom validation action in the actions array, which runs after the build completes.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// build-tokens.js</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> createContrastTransform <span class="token keyword">from</span> <span class="token string">'./lib/transforms/contrast.js'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> createCssWithContrastFormat <span class="token keyword">from</span> <span class="token string">'./lib/formats/css-with-contrast.js'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> createValidateContrastAction <span class="token keyword">from</span> <span class="token string">'./lib/actions/validate-contrast.js'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> contrastConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">backgroundTokenName</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">foregroundTokenName</span><span class="token operator">:</span> <span class="token string">'foreground'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerTransform</span><span class="token punctuation">(</span><span class="token function">createContrastTransform</span><span class="token punctuation">(</span>contrastConfig<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token function">createCssWithContrastFormat</span><span class="token punctuation">(</span>contrastConfig<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerAction</span><span class="token punctuation">(</span><span class="token function">createValidateContrastAction</span><span class="token punctuation">(</span>contrastConfig<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">transforms</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/kebab'</span><span class="token punctuation">,</span> <span class="token string">'color/add-contrast'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-with-contrast'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token literal-property property">actions</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'validate-contrast'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'🎨 Building design tokens...\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">try</span> <span class="token punctuation">{</span>
  <span class="token keyword">await</span> sd<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'✅ Build complete!\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'❌ Build failed:'</span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
  process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You'll need to set <code>backgroundTokenName</code> to specify which property holds your background colour. It defaults to <code>'background'</code> but can be changed to <code>'bg'</code>, <code>'surface'</code>, or whatever your design system uses. The <code>foregroundTokenName</code> works the same way, defaulting to <code>'foreground'</code>. Pass the config object to all the transform, format, and action creators, and all downstream processing will automatically use your configured names.</p>
<h3 id="package-scripts" tabindex="-1">Package Scripts</h3>
<p>Let's add some handy npm scripts for less typing.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"design-system-tokens"</span><span class="token punctuation">,</span>
  <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"module"</span><span class="token punctuation">,</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"build:tokens"</span><span class="token operator">:</span> <span class="token string">"node build-tokens.js"</span><span class="token punctuation">,</span>
    <span class="token property">"validate:tokens"</span><span class="token operator">:</span> <span class="token string">"node build-tokens.js"</span><span class="token punctuation">,</span>
    <span class="token property">"watch:tokens"</span><span class="token operator">:</span> <span class="token string">"nodemon --watch tokens --exec 'npm run build:tokens'"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"style-dictionary"</span><span class="token operator">:</span> <span class="token string">"^4.0.0"</span><span class="token punctuation">,</span>
    <span class="token property">"colorjs.io"</span><span class="token operator">:</span> <span class="token string">"^0.5.0"</span><span class="token punctuation">,</span>
    <span class="token property">"nodemon"</span><span class="token operator">:</span> <span class="token string">"^3.0.0"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="real-world-example" tabindex="-1">Real-World Example</h2>
<p>Let's look at adding a new button variant.</p>
<h3 id="adding-a-%22success%22-button" tabindex="-1">Adding a &quot;Success&quot; Button</h3>
<pre class="language-json"><code class="language-json"><span class="token comment">// tokens/color/component.json</span>
<span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#10b981"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Success button background"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="build-output" tabindex="-1">Build Output</h3>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">npm</span> run build:tokens
🎨 Building design tokens<span class="token punctuation">..</span>.

🔍 Validating colour contrast<span class="token punctuation">..</span>.

✅ <span class="token number">3</span> color combinations pass WCAG AA

✅ All auto-generated colour combinations meet WCAG AA standards</code></pre>
<h3 id="generated-css" tabindex="-1">Generated CSS</h3>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--button-success-background</span><span class="token punctuation">:</span> #10b981<span class="token punctuation">;</span>
  <span class="token property">--button-success-foreground-aa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 5.89:1 */</span>
  <span class="token property">--button-success-foreground-aaa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 5.89:1 */</span>
  <span class="token comment">/* ⚠️  button-success does not meet AAA standards (requires 7:1) */</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="testing-chosen-foreground-colours" tabindex="-1">Testing Chosen Foreground Colours</h3>
<p>When you define chosen foreground colours, the system generates AA/AAA pairs automatically, tests your chosen colours, and reports everything:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">npm</span> run build:tokens
🎨 Building design tokens<span class="token punctuation">..</span>.

🔍 Validating colour contrast<span class="token punctuation">..</span>.

✅ <span class="token number">3</span> color combinations pass WCAG AA

⚠️  <span class="token number">2</span> color combinations don<span class="token string">'t meet WCAG AAA:

   button-primary
   └─ 4.78:1 (requires 7:1 for AAA)
   button-light
   └─ 8.23:1 (requires 7:1 for AAA)

⚠️  2 chosen foreground colours don'</span>t meet WCAG AA:

   button-primary
   └─ Chosen: <span class="token comment">#ffffff - 4.39:1 (requires 4.5:1)</span>
   button-light
   └─ Chosen: <span class="token comment">#1e3a8a - 3.12:1 (requires 4.5:1)</span>

✅ All auto-generated colour combinations meet WCAG AA standards</code></pre>
<p>Generated CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Primary button with white text chosen by design */</span>
  <span class="token property">--button-primary-background</span><span class="token punctuation">:</span> #407ac2<span class="token punctuation">;</span>
  <span class="token property">--button-primary-foreground-aa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 4.78:1 (auto-generated) */</span>
  <span class="token property">--button-primary-foreground-aaa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 4.78:1 (auto-generated) */</span>
  <span class="token property">--button-primary-foreground</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span> <span class="token comment">/* ❌ 4.39:1 (predefined value) */</span>

  <span class="token comment">/* Light background with dark blue chosen by design */</span>
  <span class="token property">--button-light-background</span><span class="token punctuation">:</span> #e0e7ff<span class="token punctuation">;</span>
  <span class="token property">--button-light-foreground-aa</span><span class="token punctuation">:</span> #1e3a8a<span class="token punctuation">;</span> <span class="token comment">/* 8.23:1 (auto-generated) */</span>
  <span class="token property">--button-light-foreground-aaa</span><span class="token punctuation">:</span> #1e3a8a<span class="token punctuation">;</span> <span class="token comment">/* 8.23:1 (auto-generated) */</span>
  <span class="token property">--button-light-foreground</span><span class="token punctuation">:</span> #1e3a8a<span class="token punctuation">;</span> <span class="token comment">/* ❌ 3.12:1 (predefined value) */</span>

  <span class="token comment">/* Success button without chosen foreground */</span>
  <span class="token property">--button-success-background</span><span class="token punctuation">:</span> #10b981<span class="token punctuation">;</span>
  <span class="token property">--button-success-foreground-aa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 5.89:1 */</span>
  <span class="token property">--button-success-foreground-aaa</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span> <span class="token comment">/* 5.89:1 */</span>
<span class="token punctuation">}</span></code></pre>
<p>The <code>foreground-aa</code> and <code>foreground-aaa</code> variables are always auto-generated and
guaranteed to meet their respective standards. The <code>foreground</code> variable is
optional and only appears in the CSS if you've defined a foreground token. If
your chosen <code>foreground</code> colour fails AA, you'll see a <code>❌</code> symbol in the CSS
comment and a warning in the terminal output. The build never fails because of
chosen colours and you always have the safe <code>foreground-aa</code> variable available as
a fallback.</p>
<hr>
<p>By moving contrast calculation from runtime CSS to build-time Style Dictionary, we generate accessible text colour pairs automatically for every background token. This outputs plain CSS values that work everywhere, with built-in validation against WCAG standards at build time.</p>
<p>For the complete working example with all scripts, <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/16-color-contrast">check out the GitHub repository</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>&#39;The Dig&#39; - Front-End Archaeology as a Service</title>
      <link href="https://www.alwaystwisted.com/articles/introducing-the-dig-front-end-code-archaeology-as-a-service.html"/>
      <updated>2026-06-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/introducing-the-dig-front-end-code-archaeology-as-a-service.html</id>
      <content type="html">
        <![CDATA[
        <p>After more than a decade consulting in other people's codebases, I've seen it all: jQuery from 2009, dependencies untouched since the Obama administration, and CSS full of browser hacks no one dares to touch.</p>
<p>Here's what I've learned: legacy code isn't something to be embarrassed about. It's a record of the decisions, constraints, and compromises that got your product this far.</p>
<p>That's the thinking behind The Dig (think less treasure hunt, more careful excavation).</p>
<p>The Dig is a front-end code archaeology service that helps teams understand, document, and modernise a legacy front-end codebase without breaking production.</p>
<p>If every change feels riskier than it should, this is the work The Dig is built for.</p>
<h2 id="what-is-front-end-archaeology%3F" tabindex="-1">What Is Front-End Archaeology?</h2>
<p>When you inherit a codebase, you're not just reading code. You're also excavating years of decisions, browser constraints, team habits, workarounds and more.</p>
<p>Every browser hack tells a story. Every <code>!important</code> had a reason. Every &quot;temporary&quot; solution that survived three product cycles reveals the pressures your team faced.</p>
<p>Front-end archaeology is the practice of approaching legacy code with curiosity instead of judgement.</p>
<p>It asks:</p>
<ul>
<li>Why was this written this way?</li>
<li>What problem was it solving?</li>
<li>What can we learn from it?</li>
<li>What's safe to change, and what's going to break?</li>
</ul>
<p>It's the difference between demolition and renovation (or conservation).</p>
<h2 id="the-problem-with-%22just-rewrite-it%22" tabindex="-1">The Problem With &quot;Just Rewrite It&quot;</h2>
<p>I've seen enough rewrite projects to be sceptical of the idea that starting over is always the cleanest answer.</p>
<p>A rewrite sounds good at the beginning. In practice, it can often become a long and expensive project where teams maintain two systems while still trying to ship everything else.</p>
<p>That's usually when the hidden costs show up:</p>
<ul>
<li>Timelines stretch</li>
<li>Budgets grow</li>
<li>Features get lost in translation</li>
<li>Confidence drops</li>
<li>The original problem is still there, just wrapped in a new framework</li>
</ul>
<p>I'm not saying rewrites are never the right answer. I am saying they're usually the first answer people reach for, not the best one.</p>
<p>Sometimes a rewrite is necessary. Most of the time, teams need clarity first.</p>
<p>Technical debt does not improve with age, but teams cannot stop delivery to fix everything at once.</p>
<p>The Dig aims to give you a way to improve safely while work continues.</p>
<h2 id="who-this-is-for" tabindex="-1">Who This Is For</h2>
<p>The Dig is for teams that know their codebase needs attention but do not want to jump straight into a rewrite.</p>
<p>It is most useful when you are inheriting code, or when you need to improve what you already have without breaking everything in the process.</p>
<p>If that sounds familiar, archaeology is probably a better starting point than another rewrite debate.</p>
<h2 id="what-the-dig-offers" tabindex="-1">What The Dig Offers</h2>
<p>I review your codebase layer by layer, with context first and judgement second. Each area is reviewed on its own, then tied back to a practical plan.</p>
<h3 id="css-fossils" tabindex="-1">CSS Fossils</h3>
<p>CSS that has outlived the browser it was written for: old IE hacks, stale vendor prefixes, float-era layout workarounds, and styles that no longer do useful work. The goal is not to delete everything old on sight, but to work out what can be removed now, what should be modernised in place, and what needs a more cautious plan. Some artefacts belong in the museum, not in production.</p>
<h3 id="dependency-archaeology" tabindex="-1">Dependency Archaeology</h3>
<p>Codebases often accumulate packages the same way old cupboards accumulate cables. This means unused, duplicated, out-of-date packages adding unnecessary bundle weight, and dependency sprawl that nobody fully understands any more, which makes even small changes feel risky. If you've ever opened <code>package.json</code> and wondered why there are four date libraries, you already know the feeling. You get guidance on what to remove first for the biggest maintenance and bundle-size wins.</p>
<h3 id="dead-code-detection" tabindex="-1">Dead Code Detection</h3>
<p>Legacy codebases usually contain more than one kind of ghost. I map unused exports, functions, and components, unreachable paths, orphaned files, and feature flags that were never properly retired, along with old commented-out fragments that build up and make a codebase harder to read. The key is separating truly dead code from code that only looks dead because it runs on awkward or low-frequency paths.</p>
<h3 id="pattern-erosion" tabindex="-1">Pattern Erosion</h3>
<p>This is where codebase drift shows up. A team starts with one pattern, but over time several versions of the same idea appear side by side: diverging component patterns, multiple solutions to the same problem, naming or state-management drift. This is often where day-to-day maintenance costs quietly stack up, and it usually feeds directly into a pattern consolidation plan.</p>
<h3 id="performance-artefacts" tabindex="-1">Performance Artefacts</h3>
<p>Some of the most useful archaeology is invisible until it hurts. This includes render-blocking resources, unused JavaScript and CSS, legacy polyfills for browsers you no longer support, and missed image optimisation opportunities. These issues are rarely dramatic in isolation, but together they create steady drag on user experience and team velocity.</p>
<h2 id="how-it-works" tabindex="-1">How It Works</h2>
<h3 id="1.-discovery" tabindex="-1">1. Discovery</h3>
<p>We start with a conversation about what is working, what is blocking delivery, and what you need next. This is where I understand the shape of the problem: which teams own which parts, where changes feel risky, and what success looks like for you. This sets scope and priorities so the excavation focuses on what actually matters.</p>
<h3 id="2.-the-excavation" tabindex="-1">2. The Excavation</h3>
<p>Then I run the analysis. That includes automated tools, manual review, and historical context gathering, including ReliCSS for CSS archaeology, dependency analysis, dead code detection, bundle analysis, and custom pattern checks where needed. Tools help surface the issues, but interpretation is the value. The goal is turning findings into decisions your team can act on safely, not just listing problems.</p>
<h3 id="3.-the-report" tabindex="-1">3. The Report</h3>
<p>You get a comprehensive audit with the top findings, cost assessment, and a prioritised roadmap of what to tackle first and why. Each recommendation is framed by risk, effort, and impact so you can improve safely while delivery continues. You also get the language and context your team needs to align across engineering, product, and leadership, plus a walkthrough if useful so everyone leaves with the same understanding.</p>
<h2 id="what-makes-this-different" tabindex="-1">What Makes This Different</h2>
<p>Tools can list dependencies, flag dead code, and surface performance issues. I use those tools too.</p>
<p>What they cannot do is prioritise findings in your context. They do not know which parts are load-bearing, which risks are immediate, or what your team can realistically change next.</p>
<p>That human judgement is the core of The Dig.</p>
<h2 id="the-book" tabindex="-1">The Book</h2>
<p>I'm also writing a book based on these processes and tools.</p>
<p>The aim is a practical field guide for teams and consultants who need to
modernise legacy front-end systems without breaking everything.</p>
<p>It is not a theory book and not a rewrite manifesto.</p>
<p>The structure is currently planned around the same stages I use in client work:</p>
<ul>
<li><strong>Mindset:</strong> how to approach legacy code with context, not blame</li>
<li><strong>Survey:</strong> how to map CSS, JavaScript, dependencies, and architecture drift</li>
<li><strong>Classification:</strong> how to label findings by risk, effort, and impact</li>
<li><strong>Decision making:</strong> how to choose between remove, refactor, isolate, or keep</li>
<li><strong>Communication:</strong> how to present findings to engineering, product, and leadership</li>
<li><strong>Roadmapping:</strong> how to phase modernisation work while product delivery continues</li>
</ul>
<p>I'll also be including templates for audit checklists, finding categories, and reporting formats teams can adapt.</p>
<h2 id="ready-to-start-digging%3F" tabindex="-1">Ready To Start Digging?</h2>
<p>Every legacy codebase has hidden risk and hidden opportunity.</p>
<p>The goal is not to judge the past. The goal is to understand what you have now, reduce risk, and make better technical decisions from here.</p>
<p>If you want help excavating your front-end codebase and uncovering what's really holding your team back, <a href="/contact/">get in touch</a> and tell me what your team is wrestling with.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>ReliCSS Update: New Tools for Front-End Archaeology</title>
      <link href="https://www.alwaystwisted.com/articles/relicss-update-new-tools-for-front-end-archaeology.html"/>
      <updated>2026-05-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/relicss-update-new-tools-for-front-end-archaeology.html</id>
      <content type="html">
        <![CDATA[
        <p>A couple of months ago now I released a little tool I've been working on over
the years for some specific client work. <a href="https://www.alwaystwisted.com/relicss/">ReliCSS</a>
was focused on finding browser hacks, old techniques and fossils in old
stylesheets.</p>
<p>But over the years I have also found myself needing other tool to help dig into
codebases as part of a front-end archaeology process.</p>
<p>Legacy CSS problems are rarely just one thing.</p>
<p>You won't only find an old IE hack. Chances are you could also find repeated
hardcoded values that should be variables, duplicated declarations that make
files noisier than they need to be, and code structures that need a bit of
untangling before they become useful across systems.</p>
<p>So this is a proper ReliCSS update.</p>
<p>Same front-end archaeology mindset. More tools for handier excavation.</p>
<h2 id="what's-new-in-relicss" tabindex="-1">What's New in ReliCSS</h2>
<p>ReliCSS is now a suite of small, focused front-end archaeology tools rather than
a single, specific tool.</p>
<h3 id="1%3A-can-i-re-use" tabindex="-1">1: Can I Re-Use</h3>
<p>This one audits a stylesheet for hardcoded literal values and flags any likely custom property opportunities.</p>
<p>In practical terms, it helps answer:</p>
<ul>
<li>Where you've already got a variable but people are still hardcoding values?</li>
<li>Where values are repeated enough times that they should probably become a
variable or design token?</li>
<li>Where standardisation will reduce drift across components?</li>
</ul>
<p>If you're trying to move a legacy codebase toward a cleaner css custom property
or design tokens model, this can help give you a strong first pass before deeper refactoring.</p>
<h3 id="2%3A-css-de-dupe" tabindex="-1">2: CSS De-Dupe</h3>
<p>This little tool helps find repeated declarations inside the same selector.</p>
<p>It's not trying to be a full linting setup. It's simply trying to spot obvious
maintenance noise quickly.</p>
<p>The kind of duplication that creeps in during years of edits, fixes, and &quot;just ship it&quot; patches.</p>
<p>That means you can trim repeated lines, reduce confusion, and make selectors easier to reason about.</p>
<h3 id="3%3A-fossil-tokeniser" tabindex="-1">3: Fossil Tokeniser</h3>
<p>The Fossil Tokeniser helps convert legacy CSS custom properties into design tokens JSON in DTCG format.</p>
<p>You can paste older variable sets and generate structured output you can
actually work with in modern design token workflows. It also handles light and dark
theme output, so migration work does not immediately collapse into one giant
manual sorting exercise.</p>
<p>This is especially useful if you've inherited &quot;token like&quot; CSS variables and
need to move them into something more systematic, or are starting on your Design
Systems journey with an existing codebase.</p>
<h3 id="4%3A-code-scrolls" tabindex="-1">4: Code Scrolls</h3>
<p>Code Scrolls is a small group of JavaScript bookmarklets for quick front-end inspection tasks.</p>
<p>I originally wrote about these in an earlier <a href="https://www.alwaystwisted.com/articles/a-few-web-developer-bookmarklets/">blog post with other
bookmarklets</a>.
They're now (also) living as part of the ReliCSS site, which made sense because
they share the same front-end archaeology mindset. Practical tools for digging into what's
actually on the page.</p>
<p>These bookmarklets help with:</p>
<ul>
<li>toggling JS/no-JS states</li>
<li>inspecting inline CSS and inline styles</li>
<li>identifying external resources loaded from 3rd party domains</li>
</ul>
<p>They're intentionally lightweight and can be useful when you want fast results. Copy a bookmarklet, add it to your browser bar, and run it on any page you're investigating.</p>
<h2 id="input-workflows-got-better" tabindex="-1">Input Workflows Got Better</h2>
<p>In the <a href="https://www.alwaystwisted.com/articles/introducing-relicss-a-tool-for-front-end-archaeology">introduction
post</a>,
I mentioned I wanted to move beyond paste only input.</p>
<p>That has now &quot;shipped&quot;.</p>
<p>Across the core tools, ReliCSS now supports:</p>
<ul>
<li>pasted CSS (the original input)</li>
<li>uploaded files</li>
<li>URL scanning for stylesheets/pages</li>
</ul>
<h2 id="quality-of-life-updates" tabindex="-1">Quality of Life Updates</h2>
<p>A few updates are less flashy but very useful in day-to-day use:</p>
<ul>
<li>dedicated sample files for the various front-end archaeology tools.</li>
<li>shared input handling patterns across tools for consistency.</li>
<li>updated navigation and homepage structure so each tool is easier to discover and use.</li>
</ul>
<h2 id="why-this-direction" tabindex="-1">Why This Direction</h2>
<p>Front-end archaeology is rarely about one dramatic bug. It's usually a pile of
medium sized issues that have accumulated over years.</p>
<p>One obsolete prefix here. Three repeated values there. A duplicated declaration
somewhere else. A possible design token structure that's almost useful, but not quite.</p>
<p>ReliCSS is evolving around the reality of dealing with mature, legacy, fragile codebases.</p>
<p>The goal, however, is still the same.</p>
<p>Help you separate load bearing CSS from historical cruft, make informed decisions, and modernise without ripping out context you still need.</p>
<h2 id="what's-next" tabindex="-1">What's Next</h2>
<p>I'm still working toward the bigger roadmap items, especially command line tools
support for local workflows and continuous integration.</p>
<p>The browser-based workflow remains the foundation for now, and everything still runs client-side, so your code stays on your machine.</p>
<p>If you've already tried ReliCSS, thank you for the feedback so far (🙏🖤). It's shaped this update directly.</p>
<p>If you haven't tried it yet, you can dig in here: <a href="https://www.alwaystwisted.com/relicss/">alwaystwisted.com/relicss</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Linting Your Design Tokens - The Where And The When</title>
      <link href="https://www.alwaystwisted.com/articles/where-to-lint-design-tokens.html"/>
      <updated>2026-05-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/where-to-lint-design-tokens.html</id>
      <content type="html">
        <![CDATA[
        <p>In <a href="/articles/linting-your-design-tokens/">a previous article</a>, I covered &quot;what&quot;
could lint and &quot;why&quot; this all matters for design tokens. This article covers the
&quot;where&quot; in your workflow those checks should live, and &quot;when&quot; each one pays off.</p>
<p>The short answer is that you should lint as early as possible, and (if possible)
at multiple points. But where &quot;as early as possible&quot; actually is could be quite
different depending on your workflow and team structure and on who owns the
tokens at any given moment, and that shifts as design tokens move through your
workflow.</p>
<h2 id="where-do-your-tokens-live%3F" tabindex="-1">Where Do Your Tokens Live?</h2>
<p>Before thinking about when to lint, I think it's worth being clear about where
your tokens originate, because the earliest possible point could be different
depending on who owns the &quot;source of truth&quot; for your design tokens.</p>
<h3 id="design-tool-first" tabindex="-1">Design Tool First</h3>
<p>Your Design Tokens live in a design tool such as Figma, Penpot, or something
similar. Managed using Figma Variables, Penpot’s built-in token features,
plugins like Tokens Studio, or other integrations, tokens are exported or synced
to a repository. Designers own the canonical values. The lint check closest to
the source could live in the design tool itself, or fires when tokens are synced to
code.</p>
<h3 id="code-first" tabindex="-1">Code First</h3>
<p>The Design Tokens live in a structured file in the codebase such as a <a href="https://www.designtokens.org">DTCG</a>
formatted <code>tokens.json</code>, a Style Dictionary config, or similar. Engineers or
design token maintainers own them. The earliest linting point is the editor or
something like a pre-commit hook.</p>
<h3 id="product-code-%2F-native-variables-%2F-preprocessors" tabindex="-1">Product-code / Native Variables / Preprocessors</h3>
<p>Tokens live directly in the product code as CSS custom properties, variables in
preprocessors like Sass or Less, Swift constants, or other native variables
defined in platform specific files. Linting happens in the relevant layer: via
Stylelint for CSS, linter plugins for preprocessors, SwiftLint for Swift, or
similar tools for other languages, often at the editor, build, or continuous
integration(CI) step. This is common in smaller teams or systems that grew
from an existing codebase, where tokens are tightly coupled to implementation.</p>
<p>Many teams could use a mix of these in practice. For example, designers might own
foundational tokens, while developers and designers would collaborate on semantic
tokens like &quot;primary button background&quot; or &quot;error text color.&quot; Product teams may
manage component level tokens for their specific features or brands. The way your team
splits ownership and responsibility (if at all) will determine where linting
would be most effective and who needs to see (and fix) the results when something fails.</p>
<h2 id="the-cost-of-finding-problems-late" tabindex="-1">The Cost of Finding Problems Late</h2>
<p>There's a principle in software called <a href="https://en.wikipedia.org/wiki/Shift-left_testing">&quot;shift
left&quot;</a> that's the idea that bugs are
cheaper to fix the earlier you catch them.</p>
<p>Design tokens are no exception.</p>
<p>A problem caught at the source would take seconds to fix. The same problem
caught in a production incident will take hours, affects real users, and generates
the kind of incident report that could ruin somebody's afternoon.</p>
<table>
<thead>
<tr>
<th>Stage</th>
<th>Who finds it</th>
<th>Approximate cost</th>
</tr>
</thead>
<tbody>
<tr>
<td>At the source</td>
<td>Token owner</td>
<td>Seconds, fix in place</td>
</tr>
<tr>
<td>Pre-commit</td>
<td>Whoever commits</td>
<td>Minutes, fix before committing</td>
</tr>
<tr>
<td>CI pipeline</td>
<td>Team, via PR</td>
<td>10–30 min, fix, push, wait for pipeline</td>
</tr>
<tr>
<td>Production</td>
<td>Users</td>
<td>Potentially hours, hotfix, deploy, post-mortem</td>
</tr>
</tbody>
</table>
<p>That's not a reason to focus all your effort at the source. It's a reason to
think about linting at multiple stages, with each one catching what could have
been missed earlier. The goal is defence in depth, multiple overlapping checks so no single missed
stage is catastrophic.</p>
<h2 id="the-four-stages" tabindex="-1">The Four Stages</h2>
<p>Linting your design tokens fits nicely into four stages of the Design System workflow. At each stage, ownership shifts and with it, where the checking lives and what it can realistically catch.</p>
<h3 id="stage-1%3A-at-the-source" tabindex="-1">Stage 1: At the Source</h3>
<p><strong>Who owns the tokens here:</strong> Whoever originates them, the designer, token maintainer, or engineer.
<strong>Where the lint check lives:</strong> The design tool, the editor, or the CSS layer.</p>
<p>The goal at this stage is the same regardless of setup. Catch as many problems
as possible before they enter version control and production, while the cost of
fixing them is still near zero. But what &quot;at the source&quot; actually means is
different for every team.</p>
<h4 id="design-tool-first-1" tabindex="-1">Design Tool First</h4>
<p>The checking lives in the design tool itself, either through built-in features
or plugins that can validate results. Either way, the designer is the audience, they're the ones who can fix a naming issue or add a missing dark mode variant
before it ever reaches the repository. At this stage we can confidently test for
naming conventions, required tokens, dark mode pairing, colour contrast, format
consistency. We might not be able to check and test for a token that references
another token actually resolves correctly, or whether two tokens reference each
other in a loop. Those checks could require a more &quot;complete picture&quot; of every token
and how they relate which may only exist once the exported file lands in the
repository or codebase alongside everything else.</p>
<h4 id="code-first-1" tabindex="-1">Code First</h4>
<p>The linting lives in the editor via a plugin or JSON schema that validates token
files as you type or 'on save' giving whoever is making the change immediate feedback before
anything is committed. Because every token file is already in the repository, a
pre-commit hook (Stage 2) would effectively double as Stage 1 here. You can
validate the complete set locally, checking whether references resolve, whether
any tokens point at each other in a loop, and not just surface-level formatting.</p>
<h4 id="product-code-%2F-native-variables-%2F-preprocessors-1" tabindex="-1">Product-code / Native Variables / Preprocessors</h4>
<p>The checking lives in the relevant tooling layer, typically something like
Stylelint in the editor or as part of a build step for CSS (or equivalent linters
for preprocessors and native code). Surface level issues are well within reach,
naming convention violations, unknown custom properties, format errors in
values. Deeper structural checks are a different story. Whether one token
correctly references another, whether values make semantic sense in context, or
anything that needs the full picture of how tokens relate simply isn't available
at this layer. To get there, you'd need to extract the variables into a
structured format and lint that, at which point you're closer to a code first model.</p>
<h3 id="stage-2%3A-pre-commit-hook" tabindex="-1">Stage 2: Pre-Commit Hook</h3>
<p><strong>Who owns the tokens here:</strong> Whoever is committing. The developer, token
maintainer, or perhaps an automated sync process
<strong>Where the lint check lives:</strong> The local machine, running automatically before the commit lands</p>
<p>A <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">pre-commit hook</a>
can be the first line of defence in code. It would run automatically when someone
commits code, blocks the commit if the tests fail, and can give immediate feedback
without waiting for a CI run. The feedback loop is seconds, not minutes.</p>
<p>This is the stage where structural problems get caught. Broken references, circular dependencies, type-value mismatches. These are the issues that would break token transformation entirely — and they're cheap to fix here, expensive to trace later.</p>
<h4 id="design-tool-first-2" tabindex="-1">Design Tool First</h4>
<p>Even in a design-tool-first workflow, tokens eventually land in a repository,
either via an automated sync or a manual export commit. When they do, the
pre-commit hook fires. This is where checks that the design tool couldn't run
become possible like verifying that references between tokens actually resolve,
catching issues that only become apparent once all the token files are together
in one place. It can also cover any edits made directly in the repository that
bypassed the design tool entirely.</p>
<h4 id="code-first-2" tabindex="-1">Code First</h4>
<p>This stage is where most of the work happens. Because the full token graph is available locally, the pre-commit hook can validate everything: structure, references, types, naming, dependencies. For code-first teams, this is effectively Stage 1 and Stage 2 combined.</p>
<h4 id="product-code-%2F-native-variables-%2F-preprocessors-2" tabindex="-1">Product-code / Native Variables / Preprocessors</h4>
<p>The pre-commit hook runs Stylelint against the CSS files, catching naming violations and format issues before they're committed. Cross-token relationship checks aren't available here — those require a build step.</p>
<p>One important caveat across all models: pre-commit hooks can possibly be bypassed. A developer under pressure could skip it entirely. That's not a reason to skip this stage. It's a reason to also have Stage 3.</p>
<h3 id="stage-3%3A-ci-pipeline" tabindex="-1">Stage 3: CI Pipeline</h3>
<p><strong>Who owns the tokens here:</strong> The whole team — reviewers, maintainers, and contributors across disciplines.
<strong>Where the lint check lives:</strong> The CI pipeline, triggered on every pull request and push to <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches">protected branches</a>.</p>
<p>The CI pipeline is where you can run the full rule set. Unlike the pre-commit
hook, the CI should be mandatory and applies to every contributor (including those who
bypassed the hook), and designers or other contributors who don't commit via a
local environment at all. It's also where you can surface warnings, things that
shouldn't block a commit but should be visible to the reviewer.</p>
<p>This check has two jobs: block merges on errors, and report warnings without blocking. Most solutions surface these as a PR comment so reviewers can see what was flagged without digging through logs.</p>
<h4 id="design-tool-first-3" tabindex="-1">Design Tool First</h4>
<p>CI is particularly important here because designers typically won't run local hooks. When a sync tool opens a PR, the check is often the first real validation that runs, and crucially, both the designer and the reviewing engineer see the results, making failures a shared conversation rather than a silent block.</p>
<h4 id="code-first-3" tabindex="-1">Code First</h4>
<p>CI acts as the mandatory backstop for anything that slipped past the pre-commit hook, whether because the hook was bypassed or because a rule only makes sense to run against the full merged state rather than locally.</p>
<h4 id="product-code-%2F-native-variables-%2F-preprocessors-3" tabindex="-1">Product-code / Native Variables / Preprocessors</h4>
<p>CI validates the build output, the compiled stylesheet or the extracted custom properties — against the full rule set. This is the stage where cross-token checks become possible, if your build process generates a structured representation of the token system.</p>
<p>For this stage to be meaningful, the check needs to be a required status on pull requests targeting your main branch so nothing can be merged in until it passes. A CI check that teams can merge without fixing isn't really a check.</p>
<h3 id="stage-4%3A-a-pre-publish-gate" tabindex="-1">Stage 4: A Pre-Publish Gate</h3>
<p><strong>Who owns the tokens here:</strong> Release managers, or the automated release pipeline
<strong>Where the lint check lives:</strong> The publish step — an npm lifecycle hook, a release script, or a dedicated CI job that runs before tokens are distributed</p>
<p>Not every team publishes tokens as a package, but many design systems do. The pre-publish gate is the final safety net before external consumers receive your tokens. At this stage, ownership has effectively transferred to whoever is cutting the release and the audience for any failure is the consuming teams who depend on the token package being correct.</p>
<p>This stage should run in strict mode: warnings become errors. A warning that reaches a consuming application is someone else's problem to debug, in a codebase you don't control.</p>
<h4 id="design-tool-first-and-code-first" tabindex="-1">Design Tool First and code-first</h4>
<p>The pre-publish gate is the same regardless of where tokens originated. By this
point they've passed through Stages 1–3 and live in the repository. The publish
check validates the final output that the design tokens are self-contained, all
references resolve, and the structure matches what consuming tooling expects.</p>
<h4 id="product-code-%2F-native-variables-%2F-preprocessors-4" tabindex="-1">Product-code / Native Variables / Preprocessors</h4>
<p>If you distribute a CSS file rather than a structured token package, the equivalent is a strict validation of the compiled output before it's deployed or published to a CDN.</p>
<p>If you don't publish tokens as a package and instead build them directly into
application deploys, move the strict-mode check into your deployment pipeline,
the principle is the same, just triggered differently.</p>
<h2 id="which-stages-do-you-actually-need%3F" tabindex="-1">Which Stages Do You Actually Need?</h2>
<p>Not every team needs all four. The right combination depends on where your
design tokens live, how they flow through your process, and how much friction
you're willing to add at each step.</p>
<h3 id="if-you're-just-starting-out" tabindex="-1">If you're just starting out</h3>
<p>Stage 3 (CI pipeline) first. It should catch the most problems, would apply to
every contributor, and would require no local tooling setup. One workflow protects
the whole team regardless of how tokens are owned or edited.</p>
<h3 id="design-tool-first-%26-code-first" tabindex="-1">Design Tool First &amp; Code First</h3>
<p>For most teams, Stage 3 (CI) is essential. Add Stage 1 (design tool or editor validation) for instant feedback, and Stage 2 (pre-commit) for local safety nets. Use both if your workflow mixes design and code edits.</p>
<h3 id="product-code-%2F-native-variables-%2F-preprocessors-5" tabindex="-1">Product-code / Native Variables / Preprocessors</h3>
<p>Stage 2 (Stylelint pre-commit) + Stage 3 (CI on build output). If you need cross
token relationship checks, you'll need a build step that produces a structured
token representation to lint against.</p>
<h3 id="if-you-publish-tokens-as-a-package" tabindex="-1">If you publish tokens as a package</h3>
<p>Add Stage 4 regardless of your origin model. Once tokens are published, other teams are consuming them in codebases you don't control. If something is broken, it's their problem to debug. Warnings that slipped through at earlier stages need to become hard errors that block the release before it goes out.</p>
<h3 id="a-minimum-viable-setup-for-most-teams" tabindex="-1">A minimum viable setup for most teams</h3>
<p>Stage 2 (pre-commit) + Stage 3 (CI). This covers the core workflow for most
teams regardless of how tokens are owned or where they originate. The pre-commit
hook catches structural problems locally before anything is committed. The CI
catches if something slipped through and applies to every contributor. No design
tool integration, no package publishing pipeline, no additional tooling required
to get started.</p>
<h2 id="start-where-it-hurts" tabindex="-1">Start Where It Hurts</h2>
<p>Design token linting is most useful where your current process is most painful. If tokens are breaking in CI, start with pre-commit. If designers keep introducing naming inconsistencies, start with design tool validation. If consumers are getting broken releases, start with the pre-publish gate.</p>
<p>You don't need all four stages immediately.</p>
<p>You need the one that catches the problems you're actually having, integrated early enough that fixing them is still fast. Add more stages as your system and team grow into them.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Linting Your Design Tokens - The What And The Why</title>
      <link href="https://www.alwaystwisted.com/articles/linting-your-design-tokens.html"/>
      <updated>2026-05-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/linting-your-design-tokens.html</id>
      <content type="html">
        <![CDATA[
        <p>Design tokens are code: the single source of truth for design decisions — colour, typography, spacing, shadows — across your design system. When they're right, they keep products consistent. When they're wrong, the impact spreads quickly.</p>
<p>Consider a few common failures:</p>
<ul>
<li>A designer adds a new brand colour in Figma and syncs it to the repo, not
realising that <code>color.brand.primary</code> now references <code>color.brand.accent</code>,
which already references <code>color.brand.primary</code>.</li>
<li>A developer renames <code>spacing.component.button</code> to <code>spacing.interactive.button</code>
during a refactor and misses three references buried in component tokens.</li>
<li>Someone pairs <code>color.text.muted</code> with <code>color.surface.subtle</code> without checking
contrast, and it ships to production with a failing ratio.</li>
<li>A token called <code>color.feedback.errorDark</code> appears alongside <code>color.status.error-dark</code>, and six months later nobody knows which one the mobile team is using.</li>
</ul>
<p>These problems might not show up in design tools. They won't necessarily trigger transform errors. They simply, silently slip into your codebase, fragmenting your design system and creating technical debt.</p>
<p>Design tokens need linting, the same way CSS and JavaScript do. Not as a nice-to-have, but as a core part of your workflow.</p>
<h2 id="the-case-for-linting-design-tokens" tabindex="-1">The Case for Linting Design Tokens</h2>
<h3 id="design-tokens-are-under-protected" tabindex="-1">Design Tokens Are Under Protected</h3>
<p>Consider this workflow without linting:</p>
<p>Designer exports tokens from Figma → Developer imports into codebase → Tokens transform into CSS/Swift/etc → Webste/App ships</p>
<p>If there's a problem in the tokens, it may only appear when someone uses them, or worse, when users encounter broken styling in production.</p>
<p>With linting integrated at the right points in that workflow, problems get
caught before they travel any further at a moment that they're cheapest to fix.</p>
<h3 id="problems-design-token-linting-prevents" tabindex="-1">Problems Design Token Linting Prevents</h3>
<h4 id="the-silent-duplicate" tabindex="-1">The Silent Duplicate</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Both get shipped. Teams argue about which to use, confusion propagates, and you end up with the kind of <a href="/articles/design-token-naming-conventions/">naming inconsistency</a> that makes maintenance a nightmare.</p>
<h4 id="the-broken-reference" tabindex="-1">The Broken Reference</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.primary.dark}"</span> <span class="token punctuation">}</span> <span class="token comment">// Doesn't exist</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Transformation fails, developers spend 30 minutes debugging a reference that should never have been broken, and the PR sits blocked while someone traces it back to a rename that happened two weeks ago.</p>
<h4 id="the-accessibility-regression" tabindex="-1">The Accessibility Regression</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"textMuted"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FAFAFA"</span> <span class="token punctuation">}</span> <span class="token comment">// 1.08:1 contrast. Fails WCAG AA.</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>It ships to production, survives until an accessibility audit catches it, and then becomes an expensive retrofit, the kind that damages both the product and confidence in the design system.</p>
<h4 id="the-naming-inconsistency" tabindex="-1">The Naming Inconsistency</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary_color"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// snake_case</span>
    <span class="token property">"secondaryColor"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// camelCase</span>
    <span class="token property">"tertiary-color"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// kebab-case</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>New developers don't know the convention, so they pick one. Inconsistency compounds, tooling starts to break, and onboarding gets harder with every new addition to the system.</p>
<h2 id="why-it-matters-across-the-team" tabindex="-1">Why It Matters Across the Team</h2>
<p>Linting helps everyone involved in the workflow. Designers get faster feedback
before handoff, developers catch issues before review, and maintainers keep the
system consistent as it grows.</p>
<p>Product teams benefit too: fewer regressions, fewer accessibility misses, and
less avoidable debt.</p>
<h2 id="what-should-you-lint%3F" tabindex="-1">What Should You Lint?</h2>
<p>Design token linting rules can fall into three categories.</p>
<p><strong>Critical rules:</strong> prevent system breakage, requiring violations must be fixed.</p>
<p><strong>Quality rules:</strong> enforce consistency and best practices, producing warnings to
address.</p>
<p><strong>Nice-to-have rules:</strong> help teams work better together, improving team cohesion.
Suggestions to consider rather than requirements to meet.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The JSON examples in this article use the format most common in popular tooling — <code>value</code>, <code>type</code>, <code>description</code> without a <code>$</code> prefix. The W3C DTCG spec uses <code>$value</code>, <code>$type</code>, and <code>$description</code>. The linting concepts are the same regardless of which format your toolchain expects; the properties you check just differ by prefix.</p>
</div></div>
<h2 id="critical-rules" tabindex="-1">Critical Rules</h2>
<p>These rules prevent your design system and end products from breaking. If any of them fire, they should block commits and deployments.</p>
<h3 id="no-broken-references" tabindex="-1">No Broken References</h3>
<p>Every reference to another token must point to a path that actually exists.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue}"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Doesn't exist</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Broken references break token transformation to all platforms, meaning deployment failures and runtime errors. The most common causes are a rename that leaves stale references elsewhere, and copy-paste typos in reference paths, both of which a linter catches before anything reaches the end user.</p>
<h3 id="no-circular-references" tabindex="-1">No Circular References</h3>
<p>Tokens must not reference themselves, whether directly or through a chain.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.secondary}"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.primary}"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Circular!</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Circular references create infinite loops during transformation, breaking every platform's output format: CSS, Swift, Kotlin, all of them. They also tend to indicate a deeper architecture problem. Common causes are refactoring that creates unexpected dependencies, or a reference chain that loops back on itself.</p>
<h3 id="type-value-matching" tabindex="-1">Type-Value Matching</h3>
<p>Token values must match their declared type and be in the correct format. Mismatches come in several forms:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token number">16</span><span class="token punctuation">,</span> <span class="token comment">// ← Unitless number. Dimensions must be strings like "16px"</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"blue"</span><span class="token punctuation">,</span> <span class="token comment">// ← Not a valid colour format</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"opacity"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"disabled"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"1.5"</span><span class="token punctuation">,</span> <span class="token comment">// ← Opacity can't exceed 1</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"opacity"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Type-specific checks:</p>
<ul>
<li><strong>Colours:</strong> Valid hex (<code>#007AFF</code>), rgb, or hsl. Not arbitrary strings or named colours.</li>
<li><strong>Dimensions/Spacing:</strong> String values with the unit included (<code>&quot;16px&quot;</code>, <code>&quot;1rem&quot;</code>). A unitless number is invalid.</li>
<li><strong>Typography:</strong> Appropriate values (fontSize as number, fontWeight as number, lineHeight as ratio)</li>
<li><strong>Opacity:</strong> Values between 0 and 1</li>
<li><strong>Border radius:</strong> Numeric values, not negative</li>
<li><strong>Dimensions:</strong> No negative values for sizes or spacing</li>
</ul>
<p>Mismatched types can prevent transformation tools from doing their job, because
they won't be able to transform what they can't understand. Keeping type and value aligned
makes platform expectations explicit and catches typos and formatting mistakes
before they travel downstream.</p>
<h3 id="complete-token-structure" tabindex="-1">Complete Token Structure</h3>
<p>In practice, every token needs a well-defined <code>value</code> and a resolved <code>type</code>. The type can be defined directly on the token or inherited from a parent group, but transformation tools need to be able to determine it — if they can't, debugging becomes a guessing game.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Missing type property</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16px"</span>
      <span class="token comment">// ← Missing type property</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The complete form per the DTCG spec:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span><span class="token punctuation">,</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Incomplete metadata causes transformation failures and makes debugging painful. Enforcing whatever structure your toolchain requires keeps the system consistent and predictable across every token in the set.</p>
<h2 id="quality-rules" tabindex="-1">Quality Rules</h2>
<p>These rules enforce consistency and prevent confusion. When they trigger, they should surface as warnings for the team to address rather than hard blocks.</p>
<h3 id="naming-convention" tabindex="-1">Naming Convention</h3>
<p>All token names should follow a single consistent pattern: camelCase,
kebab-case, or whatever your team has agreed on. Mixing conventions in the same
system is going to cause real problems:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"Primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// ← Capital P breaks convention</span>
    <span class="token property">"primary_light"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// ← snake_case breaks convention</span>
    <span class="token property">"secondary-dark"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token comment">// ← kebab-case breaks convention</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Consistent naming makes tokens predictable and discoverable. Automation tools
depend on it, and inconsistency will add cognitive load for everyone working
with the system, especially newcomers who don't know which convention to reach
for.</p>
<h3 id="no-duplicate-values" tabindex="-1">No Duplicate Values</h3>
<p>If two tokens share the same value, one should reference the other rather than repeat it.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Duplicate value</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Consolidating through references means you update one place and every reference follows:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{spacing.xs}"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Duplicate values can create bloat and confusion about which token to use. They
may also reveal when someone has misunderstood the system's structure, which
makes it especially worth enforcing for colours, spacing, and typography.</p>
<h3 id="required-tokens-present" tabindex="-1">Required Tokens Present</h3>
<p>Your token system chould include essential tokens for every platform. A set that
only defines <code>primary</code> but skips <code>error</code>, <code>success</code>, and <code>warning</code> may be incomplete:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span>
    <span class="token comment">// ← Missing error, success, warning states</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>A more complete set:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"error"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FF3B30"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#34C759"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"warning"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FF9500"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Incomplete sets could lead to partial implementations that will feel inconsistent across platforms. This catches the common case where someone adds a colour but forgets the full set of semantic states that go with it.</p>
<h3 id="colour-contrast-compliance" tabindex="-1">Colour Contrast Compliance</h3>
<p>Colour token values should meet WCAG accessibility standards, but there's a catch: a linter can only check contrast between two tokens if it knows they'll be used together. That relationship isn't inherent in the tokens themselves at the primitive or semantic level.</p>
<p>The most reliable place to enforce contrast is at the component token level, where the pairing is explicit:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.primary}"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.white}"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span>
    <span class="token comment">// ← A linter can check these two against each other with confidence</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>At the semantic level, you can use a naming convention to imply the relationship — an <code>on-primary</code> token is understood to sit on top of <code>primary</code> — which gives a linter enough context to check the pair:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"onPrimary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>WCAG AA requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. AAA raises that to 7:1 and 4.5:1 respectively.</p>
</div></div>
<p>Contrast failures are one of the most common accessibility issues. The earlier they're caught in the token hierarchy, the less likely they are to reach components or users.</p>
<h3 id="dark-mode-completeness" tabindex="-1">Dark Mode Completeness</h3>
<p>Every light mode token should have a corresponding dark mode variant. A token without one leaves dark mode partially broken:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span> <span class="token punctuation">}</span>
    <span class="token comment">// ← Missing dark variant</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>A complete pairing looks like:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"backgroundDark"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#1A1A1A"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"textDark"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>This example uses a naming suffix convention. Your system may use
separate theme files, modes, or different naming patterns. The principle
remains: ensure every visual token has a dark mode equivalent.</p>
</div></div>
<p>This catches cases where designers add a light mode token but forget the dark mode equivalent, keeping both themes in sync and ensuring every user preference is respected.</p>
<h3 id="reference-depth-limits" tabindex="-1">Reference Depth Limits</h3>
<p>Token references shouldn't chain through too many layers. Following a five-hop
chain like this can be a painful nightmare for both people and tools:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"interactive"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.brand.primary}"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.palette.blue}"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"palette"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.system.blue}"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"system"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue}"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>A shallow reference is much easier to follow:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue}"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>When something breaks in a deep chain, debugging can become slow and painful.
Keeping references shallow encourages a clean and intentional hierarchy and makes
it possible to follow a token's value without opening multiple files.</p>
<h2 id="nice-to-have-rules" tabindex="-1">Nice-to-Have Rules</h2>
<p>These rules help teams work better together and maintain long-term health. They're suggestions, not requirements.</p>
<h3 id="token-documentation" tabindex="-1">Token Documentation</h3>
<p>Tokens should include descriptions that explain their purpose and intended use, not just their value.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary brand color used for CTAs, links, and key interactions. Do not use for backgrounds."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"light"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#E8F4FF"</span><span class="token punctuation">,</span>
        <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Light tint of primary, used for hover states and backgrounds. Pairs with primary.base for sufficient contrast."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Without descriptions, tokens are just values. With them, they become design guidance that explains intent, prevents misuse, and documents the decisions behind each choice. Descriptions are also machine-readable: documentation sites can pull them in automatically, design tools like Figma can surface them as tooltips, and code editors can show them as hover text. Worth adding when there's any ambiguity about when to use one token over another, or when new team members regularly have to ask.</p>
<h3 id="semantic-naming" tabindex="-1">Semantic Naming</h3>
<p>Token names should describe intent, not appearance — but this depends on which level of your token hierarchy you're at.</p>
<p>At the <strong>primitive</strong> level, appearance-based names are correct. <code>blue.500</code> is exactly the right name for a raw colour value: it describes what it is.</p>
<p>At the <strong>semantic</strong> and <strong>component</strong> levels, appearance-based names become a liability. If your semantic tokens look like this, you have a problem:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"lightBlue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue.200}"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"darkGray"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.gray.800}"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Semantic names survive design changes:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue.500}"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"subtle"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.blue.200}"</span> <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{colors.base.gray.800}"</span> <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>If the brand moves from blue to teal, <code>semantic.lightBlue</code> is now wrong in both name and implication. <code>semantic.primary.subtle</code> doesn't care what colour it resolves to. Worth flagging when semantic or component tokens are named after colours, tints, or hex values, or when a rebrand would require renaming rather than just changing values at the primitive level.</p>
<h3 id="no-unused-tokens" tabindex="-1">No Unused Tokens</h3>
<p>Tokens defined in the system should actually be referenced somewhere.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"legacy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Never used anywhere</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Unused tokens add noise without adding value. They make the system harder to understand, tempt developers to reach for the wrong thing, and inflate output file sizes. Worth flagging when tokens haven't been referenced in recent history or when design changes have made old tokens irrelevant.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>This is complex to track automatically (it would need access to consuming code), but useful as a periodic audit. It's also worth scoping this rule to semantic and component tokens only — primitive tokens may form a complete scale that's only partially referenced, or be generated automatically from tooling, so flagging them as &quot;unused&quot; would produce a lot of noise without much signal.</p>
</div></div>
<h3 id="consistent-value-formats" tabindex="-1">Consistent Value Formats</h3>
<p>Similar tokens should use consistent value representations. Mixing formats creates friction:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// hex</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"rgb(0, 81, 213)"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// rgb</span>
    <span class="token property">"tertiary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"hsl(217, 100%, 42%)"</span> <span class="token punctuation">}</span> <span class="token comment">// hsl</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Pick one and stick to it:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#0051D5"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"tertiary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#003FA3"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Tools have to handle every format you use, and contributors don't know which to reach for when adding new tokens. A single format keeps the system easy to read and process.</p>
<h3 id="token-naming-hierarchy-alignment" tabindex="-1">Token Naming Hierarchy Alignment</h3>
<p>The cleanest solution to token hierarchy is structural: keep primitives, semantic tokens, and component tokens in separate files. When each tier lives in its own file, there's no ambiguity about what belongs where. This also makes it much easier to enforce tier-specific rules — like semantic naming only applying to semantic and component files, or unused token checks skipping primitives entirely.</p>
<p>If everything lives in a single file, naming has to carry that weight instead, and it's a harder problem to solve with naming alone. A flat mix of raw colours, semantic names, and grouped semantic names is confusing:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Grouping by tier within the file at least makes the structure navigable:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"green"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This rule is a signal to consider whether your token architecture would benefit from separate files per tier. When names are doing the job that structure should be doing, it's worth revisiting the organisation rather than just enforcing a naming pattern.</p>
<h3 id="size%2Fscale-consistency" tabindex="-1">Size/Scale Consistency</h3>
<p>Tokens that represent scales tend to follow a logical progression. Irregular
jumps could make spacing feel arbitrary:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"20px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// ← Inconsistent jump</span>
    <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"28px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span> <span class="token comment">// ← Another irregular jump</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>A consistent multiplier makes the scale predictable:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 4</span>
    <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 4 × 2</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 8 × 2</span>
    <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"32px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// 16 × 2</span>
    <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"64px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span> <span class="token comment">// 32 × 2</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Consistent scales can create visual harmony and reduce guesswork. When spacing
or font sizes follow a predictable pattern, implementation may be faster and the
system will feel intentional rather than assembled piece by piece.</p>
<h3 id="platform-coverage" tabindex="-1">Platform Coverage</h3>
<p>Tokens should exist for all your target platforms, not just the primary one.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span> <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// ← Only web tokens, no mobile equivalents</span>
<span class="token punctuation">}</span></code></pre>
<p>When one platform gets a full token set and another doesn't, the gap shows in the product. Platform coverage rules make it explicit when a token is platform-specific rather than universal, and flag when new platforms join without getting the full set.</p>
<h3 id="metadata-consistency" tabindex="-1">Metadata Consistency</h3>
<p>Tokens should include consistent metadata fields beyond the core value and type: tags, aliases, and cross-references.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"#007AFF"</span><span class="token punctuation">,</span>
      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Brand primary color"</span><span class="token punctuation">,</span>
      <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"com.your-org.design-system"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"brand"</span><span class="token punctuation">,</span> <span class="token string">"interactive"</span><span class="token punctuation">,</span> <span class="token string">"semantic"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
          <span class="token property">"references"</span><span class="token operator">:</span> <span class="token string">"Brand Guidelines v2.1"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Rich metadata helps turn a token file into living documentation. Tags and references make tokens searchable, surface relationships, and help teams understand why decisions were made, with automation like &quot;show me all brand tokens&quot; possible as a bonus.</p>
<h2 id="how-severity-levels-work" tabindex="-1">How Severity Levels Work</h2>
<p>Not all linting issues are equal. A broken reference is catastrophic. A missing dark mode variant is important but may not be urgent. Most linting tools map this to three levels: errors that block progress until fixed, warnings that surface problems without stopping work, and informational suggestions that nudge without demanding anything.</p>
<h3 id="error" tabindex="-1">Error</h3>
<p>Errors block commits, PRs, and deploys. They represent problems that prevent the system from working at all — there's no safe way to proceed until they're resolved.</p>
<ul>
<li>Broken references</li>
<li>Circular dependencies</li>
<li>Type-value mismatches</li>
<li>Incomplete token structure</li>
<li>Accessibility failures</li>
</ul>
<h3 id="warning" tabindex="-1">Warning</h3>
<p>Warnings are reported but don't block. They flag issues that should be addressed, but won't immediately break anything — the kind of thing you fix in the next sprint, not right now.</p>
<ul>
<li>Naming inconsistencies</li>
<li>Duplicate values</li>
<li>Unused tokens</li>
<li>Missing dark mode variants</li>
<li>Insufficient documentation</li>
</ul>
<h3 id="info%2Fsuggestion" tabindex="-1">Info/Suggestion</h3>
<p>Suggestions are helpful guidance with no pressure attached. They point toward better practices without demanding them, useful for teams still finding their footing with a rule or working incrementally toward a standard.</p>
<ul>
<li>Nice-to-have rules</li>
<li>Best practice recommendations</li>
<li>&quot;Consider documenting this token&quot;</li>
<li>&quot;This could be simplified&quot;</li>
</ul>
<h2 id="configuring-rules-by-need" tabindex="-1">Configuring Rules by Need</h2>
<p>Not every team needs every rule. Here's how to think about building up your ruleset:</p>
<h3 id="minimum-viable-linting-(start-here)" tabindex="-1">Minimum viable linting (start here)</h3>
<ul>
<li>No broken references</li>
<li>No circular dependencies</li>
<li>Naming convention</li>
<li>Type-value matching</li>
<li>This catches 80% of real problems with minimal overhead</li>
</ul>
<h3 id="standard-linting-(most-teams)" tabindex="-1">Standard linting (most teams)</h3>
<ul>
<li>All critical rules</li>
<li>Duplicate detection</li>
<li>Accessibility compliance</li>
<li>Required tokens</li>
<li>This ensures completeness and quality</li>
</ul>
<h3 id="comprehensive-linting-(mature-systems)" tabindex="-1">Comprehensive linting (mature systems)</h3>
<ul>
<li>All previous rules</li>
<li>Dark mode pairing</li>
<li>Documentation requirements</li>
<li>Semantic naming enforcement</li>
<li>This optimizes for team productivity and long-term health</li>
</ul>
<h2 id="your-tokens-are-code" tabindex="-1">Your Tokens Are Code</h2>
<p>Design token linting is not about restricting your team. It's about protecting
your design system from silent (and not so silent) failures.</p>
<p>Without it, problems will hide until they affect users. Inconsistencies will accumulate, refactoring becomes risky, and designers and developers lose confidence in the system.</p>
<p>The rules in this article cover a full spectrum, from hard blocks on broken references and circular dependencies, through quality checks on naming and duplicate values, to softer suggestions on documentation and hierarchy. Not every team needs every rule. Start with the critical ones. Add others as your team grows into them.</p>
<p>Your design tokens are code. They deserve the same rigor. Lint them.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Token Naming Conventions: A Practical Guide</title>
      <link href="https://www.alwaystwisted.com/articles/design-token-naming-conventions.html"/>
      <updated>2026-04-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-token-naming-conventions.html</id>
      <content type="html">
        <![CDATA[
        <style>
  .at-token-structure {
    grid-column: popout;
    margin-block: 1.5rem 0rem;
  }

  .at-token-structure__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }

  .at-token-structure__part {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.55rem 0.7rem;
    min-height: 2.5rem;
    border: 1px solid #c8d2dc;
    background: #f6f8fa;
    color: #0f172a;
    box-shadow: 0 2px 0 rgba(15, 23, 42, 0.12);
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
      Liberation Mono, Courier New, monospace;
    font-size: 0.875rem;
    text-align: center;
    white-space: nowrap;
    line-height: 1.3;
    --source-color: #e8f2ff;
    --bg-lightness-adjust: l;
    --border-lightness-adjust: l - 20;
    border-color: black;
    background: white;
    border-color: hsl(
      from var(--source-color) h s calc(var(--border-lightness-adjust, l - 20))
    );
    background: hsl(
      from var(--source-color) h s calc(var(--bg-lightness-adjust, l))
    );
  }

  .at-token-structure__part:nth-child(1) {
    --source-color: #e8f2ff;
  }

  .at-token-structure__part:nth-child(2) {
    --source-color: #e9f9f0;

  }

  .at-token-structure__part:nth-child(3) {
    --source-color: #fff5e8;

  }

  .at-token-structure__part:nth-child(4) {
    --source-color: #f5ecff;

  }

  .at-token-structure__part:nth-child(5) {
    --source-color: #ffecef;

  }

  .at-token-structure__part--optional {
    border-style: dashed;
    opacity: 0.9;
  }

  @media (min-width: 48rem) {
    .at-token-structure__grid {
      grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
      align-items: start;
    }
  }

  @media (prefers-color-scheme: dark) {
    .at-token-structure__part {
      color: #f8fafc;
      box-shadow: 0 2px 0 rgba(2, 6, 23, 0.45);
      --bg-lightness-adjust: l - 85;
      --border-lightness-adjust: l - 25;
    }
  }
</style>
<p>If you have ever stared at a long token list and wondered whether a name should be <code>button-primary-bg</code>, <code>primary-button-background</code>, or <code>color-button-primary</code>, you are not alone.</p>
<p>Naming design tokens can look and feel simple right up until you have to do it for real. Choose a weak pattern and things get inconsistent fast. Choose a clear pattern and you get a shared language that helps both design and engineering move quicker.</p>
<p>There is no single correct convention. A two-person team shipping one product has very different needs from a large organisation running multiple brands across multiple platforms.</p>
<p>What you can do is pick a convention that is clear, consistent, and scalable. This article walks through the core token tiers, common naming models, and practical rules that help avoid naming drift.</p>
<h2 id="why-naming-gets-hard-faster-than-expected" tabindex="-1">Why naming gets hard faster than expected</h2>
<p>Most teams don't struggle creating tokens. They struggle to keep token meaning stable as more people and components work on the Design System.</p>
<p>You can often see multiple names emerge for the same idea:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"spacing.small"</span><span class="token punctuation">,</span> <span class="token string">"space-2"</span><span class="token punctuation">,</span> <span class="token string">"gap-md"</span><span class="token punctuation">,</span> <span class="token string">"paddingStandard"</span><span class="token punctuation">]</span></code></pre>
<p>Each name might make sense in isolation. Together, they signal a semantic drift. The naming model is no longer acting as a shared language.</p>
<p>This is why naming quality can affect delivery speed. If token intent is unclear, every usage becomes a local judgement call, and those judgement calls will accumulate into inconsistency.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The examples in this article follow the <a href="https://www.designtokens.org">Design Tokens Community Group</a> specification using <code>$value</code>, <code>$type</code>, and dot-notation aliases like <code>{color.brand.primary}</code>.</p>
</div></div>
<h2 id="what-are-design-tokens%2C-a-quick-recap" tabindex="-1">What are design tokens, a quick recap</h2>
<p>Design tokens are a tooling and platform agnostic way to store design decisions as named values: colour, spacing, typography, radius, shadows, motion, and (much) more.</p>
<p>The key difference is where and how many times you define those values.</p>
<p>Without tokens, you might use <code>#BADA55</code> in dozens of places across components, stylesheets, and design files. When that green needs to change, you might have to hunt down every instance to make sure you're updating everything that needs to be updated.</p>
<p>With tokens, you create a design token file, a JSON object following the <a href="https://www.designtokens.org">Design Tokens Community Group specification</a>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"green"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#BADA55"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>You define <code>#BADA55</code> once as <code>green.400</code>, then you can reference that name everywhere. The value is still defined somewhere, but it is defined in one place with a meaningful name and consumed by both design tools and code by reference via tooling like Tokens Studio or Style Dictionary.</p>
<p>This centralisation helps to give you three major benefits:</p>
<ul>
<li>Better consistency across UI</li>
<li>Easier theming and re-branding</li>
<li>Safer changes at scale because you update once and propagate everywhere</li>
</ul>
<p>Tokens are not just a technical detail. They are a shared language between design and development (and the whole team) that ends up in the product(s).</p>
<h2 id="the-three-token-tiers" tabindex="-1">The three token tiers</h2>
<p>Most modern token workflows follow a three-tier model. You will see different names for each tier, but the same underlying structure keeps showing up.</p>
<h3 id="tier-1---primitive-tokens" tabindex="-1">Tier 1 - Primitive tokens</h3>
<p>These are your raw values.</p>
<p>They describe what something is, not why it exists.</p>
<p>They are also referred to as reference, base, options, or global tokens.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#0066CC"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"8"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Primitives should not (imho) and are usually not consumed directly by components. They are source values for more specific design decisions and token tiers.</p>
<p>A common failure is skipping straight to component naming because it feels productive in the short term. In practice, that locks in naming decisions before your core scales are stable.</p>
<p>When possible, stabilise primitives first, attach intent later.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"core"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"dimension"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span> <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span> <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"24px"</span><span class="token punctuation">,</span> <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="tier-2---semantic-tokens" tabindex="-1">Tier 2 - Semantic tokens</h3>
<p>Also known as alias, decision, theme, or system tokens.</p>
<p>Semantic tokens can express intent. They describe why a value is used or what it is for.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{blue.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This is where tokens become resilient.</p>
<p>If brand blue changes, the semantic name can stay the same while the underlying primitive reference changes.</p>
<p>You can update once and it will change everywhere.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"layout"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"formStack"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{core.dimension.300}"</span><span class="token punctuation">,</span> <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"contentToButton"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{core.dimension.200}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="tier-3---component-tokens" tabindex="-1">Tier 3 - Component tokens</h3>
<p>Also known as &quot;component specific&quot; or contextual tokens.</p>
<p>This layer maps semantic intent to specific elements, components, and parts thereof.</p>
<p>Component tokens should always reference semantic tokens, never primitives directly. That indirection is what can keep the system flexible.</p>
<p>It is optional, but very useful in larger systems.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Component tokens give you precision. You can tune one component without creating side effects and explosions elsewhere.</p>
<h2 id="common-naming-conventions" tabindex="-1">Common naming conventions</h2>
<p>There is no universal winner ... &quot;It depends&quot;. Different teams will always optimise for different makeup, needs, and constraints.</p>
<p>These diagrams show the core layers for each convention. Real-world usage may add optional layers like state or namespace for more specificity.</p>
<h3 id="1.-category-property-modifier-(cpm)" tabindex="-1">1. Category-Property-Modifier (CPM)</h3>
<div class="at-token-structure" aria-label="CPM naming structure">
  <div class="at-token-structure__grid">
    <span class="at-token-structure__part">category</span>
    <span class="at-token-structure__part">property</span>
    <span class="at-token-structure__part">role</span>
    <span class="at-token-structure__part at-token-structure__part--optional">state</span>
  </div>
</div>
<p>This starts broad and gets more specific: category, property, role (and optionally state for interactions). It is easy to scan and keeps naming fairly lightweight.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.primary-hover}"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="2.-tier-based-naming" tabindex="-1">2. Tier-based naming</h3>
<div class="at-token-structure" aria-label="Tier naming structure">
  <div class="at-token-structure__grid">
    <span class="at-token-structure__part">primitive</span>
    <span class="at-token-structure__part">semantic</span>
    <span class="at-token-structure__part">component</span>
    <span class="at-token-structure__part">state</span>
  </div>
</div>
<p>Here, the naming pattern changes depending on the tier. Primitives hold values, semantic tokens hold intent, and component tokens hold local UI decisions, which keeps each layer focused. The diagram shows the token tiers; actual nesting depth varies (e.g., primitives are often 2 layers, while component tokens may be 3+).</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#2196F3"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{blue.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="3.-object-property-modifier-(opm)" tabindex="-1">3. Object-Property-Modifier (OPM)</h3>
<div class="at-token-structure" aria-label="OPM naming structure">
  <div class="at-token-structure__grid">
    <span class="at-token-structure__part">object</span>
    <span class="at-token-structure__part">property</span>
    <span class="at-token-structure__part">modifier</span>
    <span class="at-token-structure__part">state</span>
  </div>
</div>
<p>This one starts with the UI object, then narrows to property and variant. It tends to feel natural in component-led workflows because it mirrors how teams talk about UI day to day.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.primary-hover}"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="4.-context-first-naming" tabindex="-1">4. Context-first naming</h3>
<div class="at-token-structure" aria-label="Context-first naming structure">
  <div class="at-token-structure__grid">
    <span class="at-token-structure__part">tier</span>
    <span class="at-token-structure__part">category</span>
    <span class="at-token-structure__part">property</span>
    <span class="at-token-structure__part">modifier</span>
  </div>
</div>
<p>Context (e.g., 'brand' or 'theme') comes first, followed by category, property, and modifier. This ensures you know the layer before the specific decision. That works well when the same semantic token needs to exist across several themes or brands.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"brand"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{primitive.color.blue.500}"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="5.-a-comprehensive-structure" tabindex="-1">5. A Comprehensive Structure</h3>
<div class="at-token-structure" aria-label="Nathan Curtis taxonomy structure">
  <div class="at-token-structure__grid">
    <span class="at-token-structure__part">namespace</span>
    <span class="at-token-structure__part">category</span>
    <span class="at-token-structure__part">concept</span>
    <span class="at-token-structure__part">property</span>
    <span class="at-token-structure__part">variant</span>
    <span class="at-token-structure__part at-token-structure__part--optional">state</span>
  </div>
</div>
<p>Each segment has a specific job, from namespace through to state. This comprehensive structure allows for up to 6 layers, but start with the core 5 and add as needed for complexity. Names are longer, but they are very explicit, which helps when multiple teams and brands share the same system. Nathan Curtis's article <a href="https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676">Naming Tokens in Design Systems</a> goes much deeper on this taxonomy, it's well worth a reading (and bookmarking).</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"acme"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{acme.color.brand.primary}"</span><span class="token punctuation">,</span>
              <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="handling-variants%2C-states%2C-and-modes" tabindex="-1">Handling variants, states, and modes</h2>
<p>Whatever base naming model you choose, you still need clear, predictable state and variant placement patterns.</p>
<p>One practical way to stay coherent is to define where each concept lives in the name:</p>
<ol>
<li>Variant: what version of the same thing it is (for example <code>primary</code>, <code>secondary</code>, <code>danger</code>)</li>
<li>State: how that version is currently behaving (for example <code>hover</code>, <code>active</code>, <code>disabled</code>)</li>
<li>Mode: which environment it belongs to (for example <code>light</code>, <code>dark</code>, <code>highContrast</code>)</li>
</ol>
<p>If those three ideas float around in different positions, naming gets noisy fast.</p>
<h3 id="the-same-decision-in-different-conventions" tabindex="-1">The same decision in different conventions</h3>
<p>These examples all express the same meaning: primary button background on hover in dark mode.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button.primary.background.hover.dark"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-primary-hover-dark"</span><span class="token punctuation">,</span>
  <span class="token string">"dark.button.primary.background.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"acme.color.button.background.primary.hover.dark"</span><span class="token punctuation">,</span>
  <span class="token string">"theme.dark.component.button.primary.background.hover"</span>
<span class="token punctuation">]</span></code></pre>
<p>Pick one ordering model and enforce it consistently. Mixing these patterns inside one system is where discoverability starts to break down.</p>
<h3 id="variants" tabindex="-1">Variants</h3>
<p>Variants describe alternatives at the same hierarchy level, not interaction changes.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button.primary.background"</span><span class="token punctuation">,</span>
  <span class="token string">"button.secondary.background"</span><span class="token punctuation">,</span>
  <span class="token string">"button.danger.background"</span>
<span class="token punctuation">]</span></code></pre>
<p>Equivalent variant naming in other conventions:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button-background-primary"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-secondary"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-danger"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.primary"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.secondary"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.danger"</span>
<span class="token punctuation">]</span></code></pre>
<h3 id="states" tabindex="-1">States</h3>
<p>States represent interaction or status changes for the same UI element. Keep state terms predictable (<code>hover</code>, <code>active</code>, <code>focus</code>, <code>disabled</code>) so engineers can find related tokens quickly.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button.primary.background.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"button.primary.background.active"</span><span class="token punctuation">,</span>
  <span class="token string">"button.primary.background.disabled"</span><span class="token punctuation">,</span>
  <span class="token string">"button.primary.background.focus"</span>
<span class="token punctuation">]</span></code></pre>
<p>The same state grouping works across naming styles:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button-background-primary-hover"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-primary-active"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-primary-focus"</span><span class="token punctuation">,</span>
  <span class="token string">"button-background-primary-disabled"</span>
<span class="token punctuation">]</span></code></pre>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"component.button.background.primary.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.primary.active"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.primary.focus"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.background.primary.disabled"</span>
<span class="token punctuation">]</span></code></pre>
<h3 id="scale-sizes" tabindex="-1">Scale sizes</h3>
<p>Scale tokens create consistent step-based sizing. Whether you use <code>xs-xl</code> labels or numeric steps, use one scale pattern and apply it everywhere to avoid drift.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token string">"spacing.sm"</span><span class="token punctuation">,</span>
  <span class="token string">"spacing.md"</span><span class="token punctuation">,</span>
  <span class="token string">"spacing.lg"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>For type scales, the same rule applies: keep naming sequential so size relationships are obvious at a glance.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"font.size.sm"</span><span class="token punctuation">,</span> <span class="token string">"font.size.md"</span><span class="token punctuation">,</span> <span class="token string">"font.size.lg"</span><span class="token punctuation">]</span></code></pre>
<h3 id="modes-and-themes" tabindex="-1">Modes and themes</h3>
<p>Modes are contextual variants of the same decision (for example light and dark). The token purpose stays the same, only the value changes per mode.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"color.background.default.light"</span><span class="token punctuation">,</span> <span class="token string">"color.background.default.dark"</span><span class="token punctuation">]</span></code></pre>
<p>Other mode-placement patterns you will see in real systems:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"light.color.background.default"</span><span class="token punctuation">,</span>
  <span class="token string">"dark.color.background.default"</span><span class="token punctuation">,</span>
  <span class="token string">"theme.light.color.background.default"</span><span class="token punctuation">,</span>
  <span class="token string">"theme.dark.color.background.default"</span>
<span class="token punctuation">]</span></code></pre>
<p>Whichever pattern you choose, keep mode placement fixed. A stable suffix or a stable prefix both work; switching between them does not.</p>
<h3 id="numbered-scales" tabindex="-1">Numbered scales</h3>
<p>Numbered scales are useful when you need many fine-grained steps, especially for colour ramps and heading systems. The key is to keep the numbering direction and increments consistent.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"font.size.heading.1"</span><span class="token punctuation">,</span>
  <span class="token string">"font.size.heading.2"</span><span class="token punctuation">,</span>
  <span class="token string">"font.size.heading.3"</span><span class="token punctuation">,</span>
  <span class="token string">"color.gray.50"</span><span class="token punctuation">,</span>
  <span class="token string">"color.gray.100"</span><span class="token punctuation">,</span>
  <span class="token string">"color.gray.200"</span>
<span class="token punctuation">]</span></code></pre>
<p>Numbered scales also appear in alternative patterns:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"size-font-heading-100"</span><span class="token punctuation">,</span>
  <span class="token string">"size-font-heading-200"</span><span class="token punctuation">,</span>
  <span class="token string">"size-font-heading-300"</span><span class="token punctuation">,</span>
  <span class="token string">"scale.type.heading.100"</span><span class="token punctuation">,</span>
  <span class="token string">"scale.type.heading.200"</span><span class="token punctuation">,</span>
  <span class="token string">"scale.type.heading.300"</span>
<span class="token punctuation">]</span></code></pre>
<h2 id="rules-that-keep-token-naming-healthy" tabindex="-1">Rules that keep token naming healthy</h2>
<p>Most strong naming systems follow a predictable anatomy: an optional prefix (namespace or context), a core meaning (category and property), optional modifiers (intent, variant, scale), and an optional suffix (state or mode).</p>
<p>You do not need every part in every token, but when a part is present it should always appear in the same position.</p>
<h3 id="1.-consistency-beats-perfection" tabindex="-1">1. Consistency beats perfection</h3>
<p>The best naming system is the one your whole team actually follows.</p>
<p>Drifting tends to start not where the convention is broken outright, but where it is ambiguous enough to invite interpretation. A token set that mixes naming styles makes it impossible to predict what a new token should be called.</p>
<p><strong>Avoid:</strong> mixing conventions across the same token tier</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"color.button.primary.default"</span><span class="token punctuation">,</span>
  <span class="token string">"button.background.primary.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"theme.dark.component.button.primary.background.default"</span>
<span class="token punctuation">]</span></code></pre>
<p><strong>Prefer:</strong> one convention applied throughout</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"component.button.primary.background.default"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.primary.background.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"component.button.secondary.background.default"</span>
<span class="token punctuation">]</span></code></pre>
<h3 id="2.-optimise-for-clarity-over-brevity" tabindex="-1">2. Optimise for clarity over brevity</h3>
<p>Autocompletion means typing long names is rarely a problem, but reading a token list at a glance still relies on human pattern recognition. Abbreviating too aggressively trades a small typing convenience for an ongoing cognitive overhead every time someone reads or audits the system.</p>
<p><strong>Avoid</strong> abbreviations that require decoding</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"btn-bg-pri-hvr"</span><span class="token punctuation">,</span> <span class="token string">"c-txt-err"</span><span class="token punctuation">,</span> <span class="token string">"sp-md"</span><span class="token punctuation">]</span></code></pre>
<p><strong>Prefer</strong> names that read on first glance</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"button-background-primary-hover"</span><span class="token punctuation">,</span> <span class="token string">"color-text-error"</span><span class="token punctuation">,</span> <span class="token string">"spacing-md"</span><span class="token punctuation">]</span></code></pre>
<h3 id="3.-keep-semantics-semantic" tabindex="-1">3. Keep semantics semantic</h3>
<p>A name like <code>color-text-red</code> describes a visual value, which means the name breaks as soon as the colour changes. A name like <code>color-text-error</code> describes intent, which stays stable even when the underlying value does not. At semantic and component levels, name for why, not what.</p>
<p><strong>Avoid:</strong> naming for the visual value</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"color.text.red"</span><span class="token punctuation">,</span> <span class="token string">"color.background.grey"</span><span class="token punctuation">,</span> <span class="token string">"color.border.green"</span><span class="token punctuation">]</span></code></pre>
<p><strong>Prefer:</strong> naming for the intent</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"color.text.error"</span><span class="token punctuation">,</span> <span class="token string">"color.background.subtle"</span><span class="token punctuation">,</span> <span class="token string">"color.border.success"</span><span class="token punctuation">]</span></code></pre>
<h3 id="4.-order-from-broad-to-specific" tabindex="-1">4. Order from broad to specific</h3>
<p>Names are easier to scan when they move from the widest concept toward specificity. This also means that alphabetically sorted token lists naturally group related tokens together, which makes auditing and searching much faster.</p>
<p><strong>Avoid:</strong> specificity before category</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"hover.primary.button.color"</span><span class="token punctuation">,</span> <span class="token string">"disabled.background.input"</span><span class="token punctuation">,</span> <span class="token string">"lg.font.heading"</span><span class="token punctuation">]</span></code></pre>
<p><strong>Prefer:</strong> broad category first, narrowing toward specificity</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"color.button.primary.hover"</span><span class="token punctuation">,</span>
  <span class="token string">"color.input.background.disabled"</span><span class="token punctuation">,</span>
  <span class="token string">"font.heading.lg"</span>
<span class="token punctuation">]</span></code></pre>
<h3 id="5.-make-names-self-explanatory" tabindex="-1">5. Make names self-explanatory</h3>
<p>A developer who has never seen your design tokens before should be able to make a reasonable guesstimate about what it does. If a name requires specific knowledge or a colleague to interpret, it is a candidate for renaming.</p>
<p><strong>Avoid:</strong> names that only make sense in context</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"token-1"</span><span class="token punctuation">,</span> <span class="token string">"c-bd-x"</span><span class="token punctuation">,</span> <span class="token string">"primary-a"</span><span class="token punctuation">]</span></code></pre>
<p><strong>Prefer:</strong> names that explain themselves</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token string">"button.border.radius"</span><span class="token punctuation">,</span>
  <span class="token string">"color.border.focus"</span><span class="token punctuation">,</span>
  <span class="token string">"color.button.background.primary"</span>
<span class="token punctuation">]</span></code></pre>
<h3 id="6.-design-for-growth" tabindex="-1">6. Design for growth</h3>
<p>Your naming model should be able to absorb more components, more themes, and potentially more brands without a heavy structural rewrite. That does not mean you need to &quot;over engineer&quot; from the start, but it does mean avoiding patterns that only work at small scale, like implicit positional meaning or naming steps after their current count.</p>
<p><strong>Avoid:</strong> patterns that hit a ceiling</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"spacing-small"</span><span class="token punctuation">,</span> <span class="token string">"spacing-smaller"</span><span class="token punctuation">,</span> <span class="token string">"spacing-new"</span><span class="token punctuation">,</span> <span class="token string">"spacing-new-2"</span><span class="token punctuation">]</span></code></pre>
<p><strong>Prefer:</strong> a scale that can always grow in either direction</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span><span class="token string">"spacing.100"</span><span class="token punctuation">,</span> <span class="token string">"spacing.200"</span><span class="token punctuation">,</span> <span class="token string">"spacing.300"</span><span class="token punctuation">,</span> <span class="token string">"spacing.420"</span><span class="token punctuation">]</span></code></pre>
<h2 id="choosing-your-convention" tabindex="-1">Choosing your convention</h2>
<p>A practical way to decide is to consider your team size, system scope, tooling, and existing patterns together.</p>
<p>Larger teams will need a stronger structure, single product systems can probably stay simpler, and tools like Figma, Tokens Studio, and your build pipeline may naturally favour one style.</p>
<p>It is also usually safer to evolve existing patterns than replace everything at once, and the best outcome comes when designers and developers both buy into the same model.</p>
<p>Start simple, document it clearly, add examples, and revisit as the system grows.</p>
<p>Token names do not need to be academically perfect. They need to be clear enough that your team can apply them without hesitation.</p>
<h2 id="keep-naming-alive-with-lightweight-governance" tabindex="-1">Keep naming alive with lightweight governance</h2>
<p>Naming is not a one time decision.</p>
<p>It is an ongoing Design System practice.</p>
<p>If you want conventions to hold up over time, define lightweight governance:</p>
<ol>
<li>One canonical naming guide with approved examples</li>
<li>A short review checklist for new tokens</li>
<li>Periodic cleanup of duplicate or ambiguous names</li>
<li>Shared ownership across design and engineering</li>
</ol>
<p>The goal is not &quot;process for process' sake&quot;.</p>
<p>A token system in a Design System that people trust is one they will actually use, and consistent naming is how that trust gets built.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Un-Sass&#39;ing My CSS: Colour Functions Without Sass</title>
      <link href="https://www.alwaystwisted.com/articles/UnSassing-my-CSS-colour-functions.html"/>
      <updated>2026-03-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/UnSassing-my-CSS-colour-functions.html</id>
      <content type="html">
        <![CDATA[
        <p>Twelve years ago in <a href="/articles/colour-me-sass-y/">Colour me Sass-y</a>, I walked through a bunch of Sass colour helpers that made day-to-day styling feel quick and effortless. Back then, Sass was the easiest route.</p>
<p>In 2026, modern CSS gives us far more native colour power than we had in 2014. So this fourth Un-Sass'ing article is a refresh of that original post. Same goals, newer tools, no preprocessor required.</p>
<h2 id="tl%3Bdr-the-short-version" tabindex="-1">TL;DR The Short Version</h2>
<p>If your Sass workflow leans heavily on colour helpers, these are the main native CSS replacements:</p>
<ul>
<li><code>rgba($color, 0.4)</code> -&gt; <code>rgb(from var(--color) r g b / 40%)</code></li>
<li><code>lighten($color, 20%)</code> -&gt; <code>hsl(from var(--color) h s calc(l + 20))</code> (Sass parity)</li>
<li><code>darken($color, 20%)</code> -&gt; <code>hsl(from var(--color) h s calc(l - 20))</code> (Sass parity)</li>
<li><code>tint($color, 20%)</code> -&gt; <code>color-mix(in srgb, var(--color) 80%, white 20%)</code> (Sass parity)</li>
<li><code>shade($color, 20%)</code> -&gt; <code>color-mix(in srgb, var(--color) 80%, black 20%)</code> (Sass parity)</li>
<li><code>adjust-hue($color, 40deg)</code> -&gt; <code>hsl(from var(--color) calc(h + 40) s l)</code></li>
<li><code>grayscale($color)</code> -&gt; <code>hsl(from var(--color) h 0% l)</code></li>
<li><code>complement($color)</code> -&gt; <code>hsl(from var(--color) calc(h + 180) s l)</code></li>
</ul>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><code>lighten()</code>/<code>darken()</code> and <code>tint()</code>/<code>shade()</code> are not the same operation in Sass. <code>lighten()</code>/<code>darken()</code> adjust HSL lightness, while <code>tint()</code>/<code>shade()</code> mix with white/black.</p>
</div></div>
<p>For me, that covers most of the old Sass colour tricks I would reach for.</p>
<p>From my original articles list, we should also include too.</p>
<ul>
<li><code>saturate($color, 20%)</code> -&gt; <code>hsl(from var(--color) h calc(s + 20) l)</code></li>
<li><code>desaturate($color, 20%)</code> -&gt; <code>hsl(from var(--color) h calc(s - 20) l)</code></li>
</ul>
<h2 id="why-this-works-better-now" tabindex="-1">Why This Works Better Now</h2>
<p>Sass gave us colour manipulation long before browsers did, now native CSS is catching/has catched up in two important ways:</p>
<ol>
<li><a href="https://www.w3.org/TR/css-color-5/#color-mix"><code>color-mix()</code></a> gives you reliable mixing for tints, shades, and blending.</li>
<li>The <a href="https://www.w3.org/TR/css-color-4/#relative-colors">relative colour syntax</a> (<code>rgb(from ...)</code>, <code>hsl(from ...)</code>) lets you derive new colours from existing tokens.</li>
</ol>
<p>Together, these unlock a workflow where one source colour can generate multiple states and themes.</p>
<h2 id="one-source-colour" tabindex="-1">One Source Colour</h2>
<p>Let's keep one core brand colour as a CSS custom property and derive everything from it.</p>
<p>A good rule of thumb: use <a href="https://www.w3.org/TR/css-color-4/#oklch-colors">OKLCH</a> for your tokens, <a href="https://www.w3.org/TR/css-color-4/#ok-lab">OKLab</a> for your mixing. OKLCH — lightness, chroma, hue — is easy to read and tweak by hand. OKLab blends more cleanly without unexpected hue shifts in the middle.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> <span class="token function">oklch</span><span class="token punctuation">(</span>62% 0.19 26<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Surfaces and emphasis */</span>
  <span class="token property">--brand-soft</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span><span class="token punctuation">,</span> white 88%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-strong</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span><span class="token punctuation">,</span> black 22%<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* States */</span>
  <span class="token property">--brand-hover</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span><span class="token punctuation">,</span> black 12%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-active</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span><span class="token punctuation">,</span> black 24%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-border</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span><span class="token punctuation">,</span> black 35%<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Alpha variants */</span>
  <span class="token property">--brand-alpha-08</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> r g b / 8%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-alpha-18</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> r g b / 18%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>With this approach, you are not storing ten unrelated hex values anymore. You are deriving values from one custom property, which makes refactoring and theming much easier.</p>
<h2 id="replacing-common-sass-colour-functions" tabindex="-1">Replacing Common Sass Colour Functions</h2>
<h3 id="rgba()" tabindex="-1"><code>rgba()</code></h3>
<p>The classic Sass version:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$brand</span></span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>
<span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token variable">$brand</span><span class="token punctuation">,</span> 20%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Native CSS equivalent:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.alert</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> r g b / 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - rgba()" src="https://codepen.io/sturobson/embed/YPGWRYE/f48f1652d5c6607abb50d5d49cc064cc?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/YPGWRYE/f48f1652d5c6607abb50d5d49cc064cc">
  Un-Sass'ing my CSS: Colour Functions - rgba()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="lighten()-and-darken()" tabindex="-1"><code>lighten()</code> and <code>darken()</code></h3>
<p>Both are built into Sass and adjust HSL lightness directly:</p>
<pre class="language-scss"><code class="language-scss"><span class="token function">lighten</span><span class="token punctuation">(</span>#6b717f<span class="token punctuation">,</span> 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">darken</span><span class="token punctuation">(</span>#6b717f<span class="token punctuation">,</span> 20%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Native CSS equivalent using relative colour syntax:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #6b717f<span class="token punctuation">;</span>

  <span class="token property">--brand-lighten-20</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> h s <span class="token function">calc</span><span class="token punctuation">(</span>l + 20<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-darken-20</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> h s <span class="token function">calc</span><span class="token punctuation">(</span>l - 20<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>For more natural-looking results, use OKLCH instead:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #6b717f<span class="token punctuation">;</span>

  <span class="token property">--brand-lighten-20</span><span class="token punctuation">:</span> <span class="token function">oklch</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>l + 0.2<span class="token punctuation">)</span> c h<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-darken-20</span><span class="token punctuation">:</span> <span class="token function">oklch</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>l - 0.2<span class="token punctuation">)</span> c h<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - lighten() / darken()" src="https://codepen.io/sturobson/embed/pvEbQpM/0acf557ff6ab01907c755d1a15fd7d97?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/pvEbQpM/0acf557ff6ab01907c755d1a15fd7d97">
  Un-Sass'ing my CSS: Colour Functions - lighten() / darken()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="tint()-and-shade()" tabindex="-1"><code>tint()</code> and <code>shade()</code></h3>
<p>These weren't built into Sass — they were commonly written as custom helpers or pulled from a library:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@function</span> <span class="token function">tint</span><span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">,</span> <span class="token variable">$percentage</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@return</span> <span class="token function">mix</span><span class="token punctuation">(</span>white<span class="token punctuation">,</span> <span class="token variable">$color</span><span class="token punctuation">,</span> <span class="token variable">$percentage</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">@function</span> <span class="token function">shade</span><span class="token punctuation">(</span><span class="token variable">$color</span><span class="token punctuation">,</span> <span class="token variable">$percentage</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@return</span> <span class="token function">mix</span><span class="token punctuation">(</span>black<span class="token punctuation">,</span> <span class="token variable">$color</span><span class="token punctuation">,</span> <span class="token variable">$percentage</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Native CSS equivalent using <code>color-mix()</code>. Use <code>srgb</code> for Sass parity, or swap to <code>oklab</code> for more natural-looking blends:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #6b717f<span class="token punctuation">;</span>

  <span class="token comment">/* srgb: closer to Sass output */</span>
  <span class="token property">--brand-tint-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> 80%<span class="token punctuation">,</span> white 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-shade-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> 80%<span class="token punctuation">,</span> black 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* oklab: better perceptual blending */</span>
  <span class="token property">--brand-tint-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> 80%<span class="token punctuation">,</span> white 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-shade-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> 80%<span class="token punctuation">,</span> black 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - tint() / shade()" src="https://codepen.io/sturobson/embed/bNweQLO/2d26c2edce25ee3de612934820ac0436?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/bNweQLO/2d26c2edce25ee3de612934820ac0436">
  Un-Sass'ing my CSS: Colour Functions - tint() / shade()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="adjust-hue()-and-complement()" tabindex="-1"><code>adjust-hue()</code> and <code>complement()</code></h3>
<p>The Sass versions:</p>
<pre class="language-scss"><code class="language-scss"><span class="token function">adjust-hue</span><span class="token punctuation">(</span>#d13400<span class="token punctuation">,</span> 40deg<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">complement</span><span class="token punctuation">(</span>#d13400<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Native CSS equivalent using relative colour syntax in <code>hsl()</code>:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>

  <span class="token property">--brand-shift-40</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>h + 40<span class="token punctuation">)</span> s l<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-complement</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> <span class="token function">calc</span><span class="token punctuation">(</span>h + 180<span class="token punctuation">)</span> s l<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - adjust-hue()" src="https://codepen.io/sturobson/embed/pvEbQaM/b3ab88307b875b4481c6c1c04ada0a3a?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/pvEbQaM/b3ab88307b875b4481c6c1c04ada0a3a">
  Un-Sass'ing my CSS: Colour Functions - adjust-hue()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - complement()" src="https://codepen.io/sturobson/embed/zxKBMWq/6d1df1d86ee14c07e54756148c81b18e?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/zxKBMWq/6d1df1d86ee14c07e54756148c81b18e">
  Un-Sass'ing my CSS: Colour Functions - complement()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="grayscale()" tabindex="-1"><code>grayscale()</code></h3>
<p>The Sass version:</p>
<pre class="language-scss"><code class="language-scss"><span class="token function">grayscale</span><span class="token punctuation">(</span>#d13400<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Native CSS equivalent:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>
  <span class="token property">--brand-gray</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> h 0% l<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - grayscale()" src="https://codepen.io/sturobson/embed/LERZXdy/c1b4b422a29e2c8dff3802d6c4fa2242?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/LERZXdy/c1b4b422a29e2c8dff3802d6c4fa2242">
  Un-Sass'ing my CSS: Colour Functions - grayscale()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="saturate()-and-desaturate()" tabindex="-1"><code>saturate()</code> and <code>desaturate()</code></h3>
<p>The Sass versions:</p>
<pre class="language-scss"><code class="language-scss"><span class="token function">saturate</span><span class="token punctuation">(</span>#d13400<span class="token punctuation">,</span> 20%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">desaturate</span><span class="token punctuation">(</span>#d13400<span class="token punctuation">,</span> 20%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Native CSS equivalent:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--brand</span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>

  <span class="token property">--brand-more-sat</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> h <span class="token function">calc</span><span class="token punctuation">(</span>s + 20<span class="token punctuation">)</span> l<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--brand-less-sat</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--brand<span class="token punctuation">)</span> h <span class="token function">calc</span><span class="token punctuation">(</span>s - 20<span class="token punctuation">)</span> l<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - saturate() / desaturate()" src="https://codepen.io/sturobson/embed/myrEQxx/5d632adefad93b47c17381b466cf577d?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/myrEQxx/5d632adefad93b47c17381b466cf577d">
  Un-Sass'ing my CSS: Colour Functions - saturate() / desaturate()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h2 id="a-practical-component-example" tabindex="-1">A Practical Component Example</h2>
<p>Here's a small button recipe that gets all of its colour states from one token.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--btn</span><span class="token punctuation">:</span> <span class="token function">oklch</span><span class="token punctuation">(</span>58% 0.2 28<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--btn-text</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>

  <span class="token property">--btn-hover</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">,</span> black 10%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--btn-active</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">,</span> black 18%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--btn-ring</span><span class="token punctuation">:</span> <span class="token function">rgb</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span> r g b / 35%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--btn-subtle-bg</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">,</span> white 90%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">,</span> black 30%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 0 <span class="token function">var</span><span class="token punctuation">(</span>--btn-ring<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button:hover</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn-hover<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button:active</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn-active<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button:focus-visible</span> <span class="token punctuation">{</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 0.25rem <span class="token function">var</span><span class="token punctuation">(</span>--btn-ring<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button--subtle</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn-subtle-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn<span class="token punctuation">)</span><span class="token punctuation">,</span> black 45%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="Un-Sass'ing my CSS: Colour Functions - button component" src="https://codepen.io/sturobson/embed/QwKEJmP/244c2622cbe756b224a293845716aa2b?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/QwKEJmP/244c2622cbe756b224a293845716aa2b">
  Un-Sass'ing my CSS: Colour Functions - button component</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>That is a full state set from one source colour, no Sass functions required.</p>
<h2 id="progressive-enhancement-and-fallbacks" tabindex="-1">Progressive Enhancement and Fallbacks</h2>
<p>Modern colour functions have excellent browser support, but if you're supporting older browsers, you'll want fallbacks. The strategy is straightforward: provide a static colour first, then enhance with <a href="https://www.w3.org/TR/css-conditional-3/#at-supports"><code>@supports</code></a>.</p>
<h3 id="basic-%40supports-fallback" tabindex="-1">Basic <code>@supports</code> fallback</h3>
<pre class="language-css"><code class="language-css"><span class="token selector">.badge</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Fallback: static colour that works everywhere */</span>
  <span class="token property">background</span><span class="token punctuation">:</span> #d13400<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@supports</span> <span class="token punctuation">(</span><span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> red<span class="token punctuation">,</span> white<span class="token punctuation">)</span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token comment">/* Enhancement: derived colours for modern browsers */</span>
  <span class="token selector">.badge</span> <span class="token punctuation">{</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> #d13400<span class="token punctuation">,</span> white 15%<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in oklab<span class="token punctuation">,</span> #d13400<span class="token punctuation">,</span> black 55%<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="browser-support" tabindex="-1">Browser support</h3>
<h4 id="color-mix" tabindex="-1"><code>color-mix</code></h4>
<p><code>color-mix()</code> allows blending two colours with a specified weight, essential for creating tints, shades, and custom colour variations without Sass.</p>
<p><baseline-status featureId="color-mix"></baseline-status></p>
<h4 id="relative-color" tabindex="-1"><code>relative color</code></h4>
<p>Relative colour syntax lets you derive new colours from existing ones using functions like <code>hsl(from var(--color) ...)</code>, enabling dynamic colour transformations directly in CSS.</p>
<p><baseline-status featureId="relative-color"></baseline-status></p>
<h2 id="fin" tabindex="-1">Fin</h2>
<p>I still like Sass. I still use Sass. But for colour work specifically, native CSS has moved from &quot;not quite there&quot; to &quot;very usable&quot;.</p>
<p>If your project can rely on modern browser support, you can now do a lot of colour manipulation directly in CSS. Meaning you're able to Un-Sass your CSS just that little bit more.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Adding Baseline Status to My Eleventy Site</title>
      <link href="https://www.alwaystwisted.com/articles/adding-baseline-status-to-my-eleventy-site.html"/>
      <updated>2026-03-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/adding-baseline-status-to-my-eleventy-site.html</id>
      <content type="html">
        <![CDATA[
        <p>As I've recently started writing about relatively new CSS and web platform features again, I wanted to show 'at a glance' browser support that's available and/or whether something is &quot;safe&quot; to use or not. A browser support table copied from somewhere else can go very stale very quickly. A screenshot would be even worse.</p>
<p>What I wanted was a 'living' component. Something that does what I needed and can easily update itself.</p>
<p>That's exactly what the <a href="https://github.com/web-platform-dx/baseline-status"><code>&lt;baseline-status&gt;</code></a> web component can do. It fetches current support data from the <a href="https://web-platform-dx.github.io/web-features/web-features/">Web Features API</a> and renders a small, self-contained component on the page.</p>
<p>Here's how it's integrated into this Eleventy (<a href="https://www.kickstarter.com/projects/fontawesome/build-awesome">Build Awesome</a>) website.</p>
<h2 id="why-baseline-over-caniuse%3F" tabindex="-1">Why Baseline over CanIUse?</h2>
<p>I've been a big fan of <a href="https://caniuse.com">Can I Use</a> since forever. It's brilliant for deeper investigation. Checking specific browser versions, finding out if something needs a flag or prefix, any know bugs or existing resrouces, or getting a wider overview of a feature.</p>
<p>But it still leaves the decision on using a new CSS feature entirely with you.</p>
<p><a href="https://web.dev/baseline">Baseline</a> is opinionated by design.</p>
<ul>
<li><strong>Limited Availability</strong> - when a feature isn't yet known to be supported across all core browsers</li>
<li><strong>Newly Available</strong> - once all core browsers have shipped support</li>
<li><strong>Widely Available</strong> - once that support has been stable for 30 months</li>
</ul>
<p>With these three states, you can make an informed decision instantly. If your teams CSS authroing guidelines stipulate only using <strong>Widely Available</strong> features, you know immediately whether you're good to go.</p>
<p>The component fetches live data from the Web Features API, so the status will update as browsers move features through these states. Folks get a clear 'on the day' answer, not a point-in-time screenshot.</p>
<h2 id="the-integration" tabindex="-1">The integration</h2>
<h3 id="installing-the-package" tabindex="-1">Installing the package</h3>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> baseline-status</code></pre>
<p>The package ships a minified, self-contained ES module (<code>baseline-status.min.js</code>) that includes everything it needs, including Lit. It's around 50KB minified (including the Lit framework). That's not ridiculously huge, but it's not something I want loading on every page either.</p>
<h3 id="copying-the-script-at-build-time" tabindex="-1">Copying the script at build time</h3>
<p>Rather than loading the component from a CDN, I copy it from <code>node_modules</code> into the build output during the Eleventy build. In <code>.eleventy.js</code>:</p>
<pre class="language-js"><code class="language-js">config<span class="token punctuation">.</span><span class="token function">addPassthroughCopy</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token string-property property">'node_modules/baseline-status/baseline-status.min.js'</span><span class="token operator">:</span>
    <span class="token string">'scripts/baseline-status.min.js'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The script ends up at <code>/scripts/baseline-status.min.js</code> in the site output. No CDN dependency, no runtime fetch to jsDelivr or unpkg, it's served straight from my own servers. The version is also pinned in <code>package.json</code>, so the component won't quietly change underneath me between builds.</p>
<p>Updating is as simple as:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> update baseline-status</code></pre>
<p>The passthrough copy should pick up the new file on the next build automatically.</p>
<h2 id="easily-%22turn-on-and-off-able%22" tabindex="-1">Easily &quot;turn on and off-able&quot;</h2>
<p>I could have just dropped the script into the bottom of my page template and called it done. But then every page would carry that extra weight, even articles that never mention browser support. Instead, I made it opt-in at the article level using Nunjucks conditionals and a frontmatter flag.</p>
<p>The shortcode checks for the frontmatter flag before rendering anything. When writing an article, I add <code>baselineStatus: true</code> to the frontmatter, then type <code>{% baselineStatus 'feature-id' %}</code> wherever I want the widget to appear.</p>
<p>If I forget to set the flag, nothing renders, which I'll spot when reviewing the article.</p>
<h3 id="the-frontmatter-flag" tabindex="-1">The frontmatter flag</h3>
<p>Any article that wants to use <code>&lt;baseline-status&gt;</code> sets a flag in its front matter:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span>
<span class="token key atrule">title</span><span class="token punctuation">:</span> <span class="token string">'My Article About a CSS Feature'</span>
<span class="token key atrule">date</span><span class="token punctuation">:</span> <span class="token datetime number">2026-03-09</span>
<span class="token key atrule">baselineStatus</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
<span class="token punctuation">---</span></code></pre>
<p>No flag, no script. It's off by default for the rest of the site.</p>
<h3 id="the-conditional-load-in-the-base-layout" tabindex="-1">The conditional load in the base layout</h3>
<p>In <code>_includes/layouts/base.njk</code>, just before <code>&lt;/body&gt;</code>, the script tag is only rendered when that flag is present:</p>
<pre class="language-njk"><code class="language-njk"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">if</span> <span class="token variable">baselineStatus</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token variable">script</span> <span class="token variable">type</span><span class="token operator">=</span><span class="token string">"module"</span> <span class="token variable">src</span><span class="token operator">=</span><span class="token string">"/scripts/baseline-status.min.js"</span><span class="token operator">></span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">script</span><span class="token operator">></span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">endif</span> <span class="token operator">%</span><span class="token punctuation">}</span></code></pre>
<p>As the script is loaded as <code>type=&quot;module&quot;</code>, it defers automatically and shouldn't block rendering. Browsers that don't support ES modules don't load it at all which is fine, because in practice those are browsers that wouldn't render the component (or probably the web platform feature) either.</p>
<h3 id="the-shortcode" tabindex="-1">The shortcode</h3>
<p>Writing raw HTML in a Markdown article is fine, but using a shortcode can keep things a little cleaner and consistent.</p>
<p>In <code>.eleventy.js</code>:</p>
<pre class="language-js"><code class="language-js">config<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">'baselineStatus'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">featureId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Only render if the page has baselineStatus flag set</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>ctx <span class="token operator">&amp;&amp;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>ctx<span class="token punctuation">.</span>baselineStatus<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">&lt;baseline-status featureId="</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>featureId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">">&lt;/baseline-status></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="using-it-in-an-article" tabindex="-1">Using it in an article</h2>
<h3 id="finding-a-feature-id" tabindex="-1">Finding a feature ID</h3>
<p>Feature IDs come from the <a href="https://github.com/web-platform-dx/web-features/tree/main/features">web-platform-dx/web-features</a> repository. The quickest way to find one is to visit <a href="https://webstatus.dev/">webstatus.dev</a>, search for the feature you're interested in, and read the ID from the URL.</p>
<p>Feature IDs don't always match what you'd expect. For example, CSS Nesting is just called <code>nesting</code> in the data, and Anchor Positioning is <code>anchor-positioning</code>. The safest approach is to search webstatus.dev for what you want - you'll find the correct ID right there in the URL.</p>
<p>Here are some common examples:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Feature ID</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://webstatus.dev/features/nesting">CSS Nesting</a></td>
<td><code>nesting</code></td>
</tr>
<tr>
<td><a href="https://webstatus.dev/features/anchor-positioning">Anchor Positioning</a></td>
<td><code>anchor-positioning</code></td>
</tr>
<tr>
<td><a href="https://webstatus.dev/features/color-mix"><code>color-mix()</code></a></td>
<td><code>color-mix</code></td>
</tr>
<tr>
<td><a href="https://webstatus.dev/features/container-queries">Container Queries</a></td>
<td><code>container-queries</code></td>
</tr>
<tr>
<td><a href="https://webstatus.dev/features/has"><code>:has()</code></a></td>
<td><code>has</code></td>
</tr>
</tbody>
</table>
<h3 id="step-by-step" tabindex="-1">Step-by-step</h3>
<p><strong>1.</strong> Add <code>baselineStatus: true</code> to the article's front matter. This loads the script on that page and only that page.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span>
<span class="token key atrule">title</span><span class="token punctuation">:</span> My Brilliant Article about Container Queries
<span class="token key atrule">baselineStatus</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
<span class="token punctuation">---</span></code></pre>
<p><strong>2.</strong> Drop the shortcode wherever you want the widget to appear:</p>
<pre class="language-njk"><code class="language-njk"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">baselineStatus</span> <span class="token string">'container-queries'</span> <span class="token operator">%</span><span class="token punctuation">}</span></code></pre>
<p><strong>3.</strong> That's it. Here's what that actually renders on this page:</p>
<p><baseline-status featureId="container-queries"></baseline-status></p>
<p>The component fetches live data from the Web Features API, so the status reflects the current state of the feature not whatever was true when I wrote the article.</p>
<h2 id="worth-it-tho%3F" tabindex="-1">Worth it tho?</h2>
<p>Since I have been regularly writing about brand new or relatively new CSS and web platform features. Yes, absolutely.</p>
<p>I like that the opt-in approach keeps the script off pages that don't need it, the shortcode keeps the authoring tidy, and serving the file myself means I'm not dependent on a third-party CDN staying online.</p>
<p>It's a small thing, but I think it can make the articles feel a little more alive, more informative.</p>
<p>Browser support data that updates itself beats a screenshot from 2024 every time.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Un-Sass&#39;ing My CSS: Native CSS Nesting</title>
      <link href="https://www.alwaystwisted.com/articles/UnSassing-my-CSS-nesting.html"/>
      <updated>2026-03-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/UnSassing-my-CSS-nesting.html</id>
      <content type="html">
        <![CDATA[
        <p>One of the features I would miss most when moving away from Sass would be nesting. There's something wonderfully clean about grouping related selectors together, keeping your code organised and reducing repetition. For years, this was the realm of preprocessors like Sass, Less, and PostCSS, but now, CSS nesting has landed in the browser, and it's time to revisit it as a core part of how we write modern CSS.</p>
<h2 id="what-is-css-nesting%3F" tabindex="-1">What is CSS Nesting?</h2>
<p>CSS nesting allows you to write child selectors within a parent selector, mirroring the DOM structure and reducing repetition. Instead of writing out full selectors each time, you nest rules and let the browser expand them into their final form.</p>
<p>Here's a simple example:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>

  <span class="token selector">.card-header</span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
    <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">.card-body</span> <span class="token punctuation">{</span>
    <span class="token property">margin-top</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The browser expands this into:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card .card-header</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card .card-body</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can nest as deeply as your structure requires (browsers support very deep nesting), though in practice you should keep nesting reasonably shallow to maintain code readability and avoid unnecessary specificity buildup.</p>
<h2 id="browser-support" tabindex="-1">Browser Support</h2>
<p>CSS nesting has solid support across modern browsers as of 2026. Chrome, Edge, Firefox, and Safari all support it. You can <a href="https://caniuse.com/css-nesting">check caniuse.com</a> for more complete details.</p>
<p><baseline-status featureId="nesting"></baseline-status></p>
<h3 id="progressive-enhancement" tabindex="-1">Progressive Enhancement</h3>
<p>CSS nesting could be another good place to think carefully about progressive enhancement. A browser that doesn't understand nesting won't just ignore the nested rules it will drop them entirely, which could mean missing <code>:hover</code> states, missing responsive adjustments, or missing theme variants. The base styles will still render, but the nested behaviour won't.</p>
<p>For most projects in 2026, your audience probably supports nesting. Chrome, Edge, Firefox, and Safari all ship with it. But if you need to support older browsers (enterprise environments, older Android WebViews, etc), you have two options. Write a layered approach with <code>@supports (selector(&amp;))</code> as a feature query, or stick with something like Sass if you want to nest by compiling down for older targets.</p>
<h2 id="how-nesting-works-in-the-browser" tabindex="-1">How Nesting Works in the Browser</h2>
<p>When a browser parses nested CSS, it expands the nested selectors relative to the parent selector. For simple cases, it's straightforward:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token selector">.card-header</span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This becomes:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card .card-header</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>However, when the parent selector has <strong>multiple selectors</strong> or <strong>complex patterns</strong>, the browser uses the <code>:is()</code> pseudo-class to handle the expansion. This is important because it affects specificity calculations.</p>
<p>For example, this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card,
.panel</span> <span class="token punctuation">{</span>
  <span class="token selector">.header</span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Gets parsed as:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:is(.card, .panel) .header</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This matters because <code>:is()</code> uses the <strong>highest specificity</strong> from its selector list for specificity calculations. If your parent is <code>.card, #featured {}</code>, the <code>:is()</code> takes the specificity of the ID, even if the nested rule only applies to <code>.card</code>.</p>
<p>For example:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">#featured,
.card</span> <span class="token punctuation">{</span>
  <span class="token selector">.header</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Becomes:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:is(#featured, .card) .header</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The <code>.header</code> inside <code>.card</code> now has ID-level specificity <code>(1,1,0)</code>. This can catch you off guard when debugging styles that won't override as expected.</p>
<p>You can explicitly reference the parent with <code>&amp;</code>, or omit it—the browser treats <code>.parent { .child {} }</code> as if you'd written <code>&amp; .child</code>, creating a descendant relationship.</p>
<p>The <code>&amp;</code> becomes essential when you need a different relationship, like pseudo-classes where no space is allowed (<code>.button { &amp;:hover {} }</code> becomes <code>.button:hover {}</code>), or when reversing the selector order (<code>.theme-dark &amp; {}</code> becomes <code>.theme-dark .parent {}</code>).</p>
<h3 id="the-ampersand-(%26)" tabindex="-1">The Ampersand (<code>&amp;</code>)</h3>
<p>The <code>&amp;</code> symbol is your key to manipulating how nesting works. It represents the parent selector and lets you compose more complex selector patterns. While you can omit <code>&amp;</code> for simple descendant selectors (the browser treats <code>.parent { .child {} }</code> as if you'd written <code>&amp; .child</code>), you'll need it explicitly for pseudo-classes, compound selectors, and other patterns where the relationship isn't a straightforward parent-child descendant.</p>
<p>You can use <code>&amp;</code> to create pseudo-class selectors:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>

  <span class="token selector">&amp;:hover</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #0056b3<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;:active</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #003d7a<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This expands to:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button:hover</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #0056b3<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button:active</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #003d7a<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can also use ⁠&amp; to create compound selectors, which is handy for state classes—but with an important caveat about BEM patterns.</p>
<p>The key limitation: Native CSS nesting does not support Sass-style selector concatenation like ⁠<code>&amp;--primary</code> or <code>⁠&amp;__element</code>. This is because in native CSS, selectors are object references, not strings. Sass treats them as strings and can concatenate them together. CSS cannot.</p>
<p>This means you can't write:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token selector">&amp;--primary</span> <span class="token punctuation">{</span>
    <span class="token comment">/* This won't work */</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Instead, you could use a compound selector with the full class name:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token selector">&amp;.button--primary</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;.button--secondary</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Which expands to:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button.button--primary</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.button.button--secondary</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Or, if you're working with BEM element selectors, keep them at the root level:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button</span> <span class="token punctuation">{</span> ... <span class="token punctuation">}</span>
<span class="token selector">.button__icon</span> <span class="token punctuation">{</span> ... <span class="token punctuation">}</span>
<span class="token selector">.button__label</span> <span class="token punctuation">{</span> ... <span class="token punctuation">}</span></code></pre>
<p>For historical context on BEM with Sass (where concatenation does work), see <a href="/articles/even-easier-bem-ing-with-sass-33/">Even Easier BEM-ing with Sass 3.3</a>.</p>
<h2 id="specificity-and-css-nesting" tabindex="-1">Specificity and CSS Nesting</h2>
<p>Here's where things get a little interesting. CSS nesting follows the same specificity rules as traditional CSS, with one important detail: the <code>&amp;</code> nesting selector calculates its specificity like the <code>:is()</code> pseudo-class it uses the <strong>highest specificity</strong> from the parent selector list, not the sum of all the selectors.</p>
<h3 id="understanding-specificity-with-nesting" tabindex="-1">Understanding Specificity with Nesting</h3>
<p>Specificity is calculated as a <a href="https://en.wikipedia.org/wiki/Tuple">tuple</a>, (ID count, class count, element count).</p>
<p>For example:</p>
<ul>
<li>A single class selector: <code>(0,1,0)</code></li>
<li>A single element selector: <code>(0,0,1)</code></li>
<li>An ID selector: <code>(1,0,0)</code></li>
</ul>
<p>When you nest, you stack these together just as you would with a descendant selector.</p>
<p>Here's the key detail: the <code>&amp;</code> selector itself takes the <strong>highest specificity</strong> from its parent rule list. For example, if the parent is <code>.foo, #bar {}</code>, the <code>&amp;</code> has the specificity of <code>#bar</code> <code>(1,0,0)</code>, even when you nest rules inside <code>.foo</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token comment">/* (0,1,0) - one class */</span>
<span class="token punctuation">}</span>

<span class="token selector">.card .card-header</span> <span class="token punctuation">{</span>
  <span class="token comment">/* (0,2,0) - two classes */</span>
<span class="token punctuation">}</span>

<span class="token selector">.card .card-header h1</span> <span class="token punctuation">{</span>
  <span class="token comment">/* (0,2,1) - two classes, one element */</span>
<span class="token punctuation">}</span></code></pre>
<p>In nested syntax, this looks cleaner, but the math is identical:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token selector">.card-header</span> <span class="token punctuation">{</span>
    <span class="token selector">h1</span> <span class="token punctuation">{</span>
      <span class="token comment">/* Still (0,2,1) */</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>While nesting can make your code more readable, deeper nesting means higher specificity, which can make overriding styles harder later. One quirk: nesting inside a selector list with an ID (like <code>.card, #featured { .header {} }</code>) wraps the list in <code>:is()</code>, lifting specificity to ID level. Keep this in mind if you spot unexpectedly high specificity when debugging.</p>
</div></div>
<h2 id="css-nesting-vs-sass-nesting" tabindex="-1">CSS Nesting vs Sass Nesting</h2>
<p>At first glance, CSS nesting and Sass nesting may look identical. You can nest selectors, use the ampersand to reference parents, and keep your code organised.</p>
<p>But, there are some important differences worth understanding.</p>
<h3 id="syntax-differences" tabindex="-1">Syntax Differences</h3>
<p>Sass nesting tends to feel more forgiving because it's a preprocessor, it compiles your code before the browser ever sees it, giving it more room to interpret and transform what you write.</p>
<p>CSS nesting, being native browser code, has to follow stricter parsing rules.</p>
<h4 id="sass-example%3A" tabindex="-1">Sass example:</h4>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.card </span><span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>

  <span class="token selector">.card-header </span><span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector"><span class="token parent important">&amp;</span>--dark </span><span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// You can also place &amp; in different positions</span>
  <span class="token selector">.theme-dark <span class="token parent important">&amp;</span> </span><span class="token punctuation">{</span>
    <span class="token property">border-color</span><span class="token punctuation">:</span> #666<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="css-nesting-equivalent%3A" tabindex="-1">CSS nesting equivalent:</h4>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>

  <span class="token selector">.card-header</span> <span class="token punctuation">{</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;.card--dark</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">.theme-dark &amp;</span> <span class="token punctuation">{</span>
    <span class="token property">border-color</span><span class="token punctuation">:</span> #666<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>They look similar, but CSS nesting has stricter parsing rules.</p>
<h3 id="important-differences" tabindex="-1">Important Differences</h3>
<h4 id="sass-has-variables%2C-mixins%2C-and-functions" tabindex="-1">Sass has variables, mixins, and functions</h4>
<p>Sass can do math, store values, reuse chunks of code with mixins, and apply conditional logic. CSS nesting is purely structural—it doesn't add any of these capabilities. That said, CSS has its own equivalents: <code>calc()</code> for math, custom properties for values, functions like <code>color-mix()</code>, and <code>@when</code>/<code>@else</code> for conditionals. Mixins are being actively developed in the CSS spec, though they're not yet available cross-browser.</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Sass can do this</span>
<span class="token property"><span class="token variable">$spacing</span></span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>

<span class="token selector">.card </span><span class="token punctuation">{</span>
  <span class="token comment">// Sass will generate these values when compiling</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token variable">$spacing</span> <span class="token operator">*</span> 2<span class="token punctuation">;</span>

  <span class="token comment">// Sass gives you mixins to</span>
  <span class="token keyword">@include</span> <span class="token function">respondTo</span><span class="token punctuation">(</span><span class="token string">'mobile'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token variable">$spacing</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token comment">/* CSS Will calculate this value in the browser */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--spacing<span class="token punctuation">)</span> * 2<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* CSS doesn't have mixins (yet) */</span>
  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="nesting-depth-and-specificity-are-more-visible-in-css" tabindex="-1">Nesting depth and specificity are more visible in CSS</h4>
<p>Nesting in both Sass and CSS increases specificity with each level, it's not unique to native CSS. The <a href="https://sass-lang.com/documentation/style-rules/#nesting">Sass documentation</a> itself warns &quot;Be aware that overly nested rules will result in over-qualified CSS that could prove hard to maintain and is generally considered bad practice.&quot; The difference is that with Sass, you might not see the compiled output regularly, so it could easier to lose track of how deep you've nested.</p>
<p>With native CSS, what you write is what the browser sees, hopefully making specificity issues more visible.</p>
<h2 id="a-practical-example%3A-building-a-component" tabindex="-1">A Practical Example: Building a Component</h2>
<p>Let's build a simple component using CSS nesting to show how it all comes together.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--alert-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--alert-border-radius</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--alert-margin-bottom</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--alert-icon-margin</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--alert-title-margin</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--alert-close-size</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--alert-success-bg</span><span class="token punctuation">:</span> #d4edda<span class="token punctuation">;</span>
  <span class="token property">--alert-success-border</span><span class="token punctuation">:</span> #c3e6cb<span class="token punctuation">;</span>
  <span class="token property">--alert-success-text</span><span class="token punctuation">:</span> #155724<span class="token punctuation">;</span>
  <span class="token property">--alert-warning-bg</span><span class="token punctuation">:</span> #fff3cd<span class="token punctuation">;</span>
  <span class="token property">--alert-warning-border</span><span class="token punctuation">:</span> #ffeaa7<span class="token punctuation">;</span>
  <span class="token property">--alert-warning-text</span><span class="token punctuation">:</span> #856404<span class="token punctuation">;</span>
  <span class="token property">--alert-danger-bg</span><span class="token punctuation">:</span> #f8d7da<span class="token punctuation">;</span>
  <span class="token property">--alert-danger-border</span><span class="token punctuation">:</span> #f5c6cb<span class="token punctuation">;</span>
  <span class="token property">--alert-danger-text</span><span class="token punctuation">:</span> #721c24<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.alert</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-border-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid transparent<span class="token punctuation">;</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-margin-bottom<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Modifier variants use &amp; for state changes */</span>
  <span class="token selector">&amp;.alert--success</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-success-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-success-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-success-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;.alert--warning</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-warning-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-warning-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-warning-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;.alert--danger</span> <span class="token punctuation">{</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-danger-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">border-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-danger-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-danger-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">/* Responsive adjustments */</span>
  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">max-width</span><span class="token punctuation">:</span> 640px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--alert-padding<span class="token punctuation">)</span> * 0.75<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Class selectors stay at the component level */</span>
<span class="token selector">.alert__icon</span> <span class="token punctuation">{</span>
  <span class="token property">margin-right</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-icon-margin<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">display</span><span class="token punctuation">:</span> inline-block<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.alert__title</span> <span class="token punctuation">{</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> bold<span class="token punctuation">;</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-title-margin<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.alert__close</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  <span class="token property">cursor</span><span class="token punctuation">:</span> pointer<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--alert-close-size<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">float</span><span class="token punctuation">:</span> right<span class="token punctuation">;</span>

  <span class="token comment">/* Nest pseudo-classes for interactive states */</span>
  <span class="token selector">&amp;:hover</span> <span class="token punctuation">{</span>
    <span class="token property">opacity</span><span class="token punctuation">:</span> 0.7<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="CSS Nesting - Alert Component" src="https://codepen.io/sturobson/embed/JoRXXGP/35fbab1dcb9e469009358889a9033360?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/JoRXXGP/35fbab1dcb9e469009358889a9033360">
  CSS Nesting - Alert Component</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>Notice how we use nesting for modifier variants (<code>&amp;.alert--success</code>) and media queries, but keep the child class selectors (<code>.alert__icon</code>, <code>.alert__title</code>, <code>.alert__close</code>) at the component level. This could keep specificity low while still grouping related interactive behaviour with the component.</p>
<h2 id="nesting-with-container-queries" tabindex="-1">Nesting with Container Queries</h2>
<p>CSS nesting becomes particularly powerful when combined with other modern CSS features like container queries. Here's a card component that adapts its layout based on the container's width, not the viewport. We'll use custom properties for consistent spacing and colors:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--card-gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--card-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--card-border-color</span><span class="token punctuation">:</span> #e0e0e0<span class="token punctuation">;</span>
  <span class="token property">--card-border-radius</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--card-shadow</span><span class="token punctuation">:</span> 0 2px 4px <span class="token function">rgba</span><span class="token punctuation">(</span>0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0<span class="token punctuation">,</span> 0.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--card-image-aspect</span><span class="token punctuation">:</span> 16 / 9<span class="token punctuation">;</span>
  <span class="token property">--card-image-radius</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--card-title-size</span><span class="token punctuation">:</span> 1.1rem<span class="token punctuation">;</span>
  <span class="token property">--card-title-margin</span><span class="token punctuation">:</span> 0 0 0.5rem 0<span class="token punctuation">;</span>
  <span class="token property">--card-text-size</span><span class="token punctuation">:</span> 0.9rem<span class="token punctuation">;</span>
  <span class="token property">--card-text-color</span><span class="token punctuation">:</span> #666<span class="token punctuation">;</span>
  <span class="token property">--card-text-line-height</span><span class="token punctuation">:</span> 1.5<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card-wrapper</span> <span class="token punctuation">{</span>
  <span class="token property">container-type</span><span class="token punctuation">:</span> inline-size<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr<span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid <span class="token function">var</span><span class="token punctuation">(</span>--card-border-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-border-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-shadow<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token selector">img</span> <span class="token punctuation">{</span>
    <span class="token property">aspect-ratio</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-image-aspect<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">object-fit</span><span class="token punctuation">:</span> cover<span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-image-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">h3</span> <span class="token punctuation">{</span>
    <span class="token property">margin</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-title-margin<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-title-size<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">p</span> <span class="token punctuation">{</span>
    <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
    <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-text-size<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-text-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-text-line-height<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token atrule"><span class="token rule">@container</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span> 400px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 200px 1fr<span class="token punctuation">;</span>
    <span class="token property">gap</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-gap<span class="token punctuation">)</span> * 1.5<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token selector">img</span> <span class="token punctuation">{</span>
      <span class="token property">aspect-ratio</span><span class="token punctuation">:</span> 2 / 1<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="CSS Nesting - Card Component" src="https://codepen.io/sturobson/embed/PwGNNZm/0c2ba50998874ef03937f9341f1f294a?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/PwGNNZm/0c2ba50998874ef03937f9341f1f294a">
  CSS Nesting - Card Component</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>The card starts as a single column with the image above the text. When the card wrapper reaches <code>400px</code>, it switches to a two-column layout with the image on the left and text on the right. Notice how the nesting keeps all the related rules together, making it clear how the component adapts.</p>
<p>This demonstrates an important advantage of CSS nesting: it lets you group related styles—including responsive adaptations—in one logical block rather than scattering them across multiple rules.</p>
<h2 id="accessibility%3A-reduced-motion-preferences" tabindex="-1">Accessibility: Reduced Motion Preferences</h2>
<p>Seeing <a href="https://bsky.app/profile/kilianvalkhof.com/post/3mgajemyv6k2f">Kilian post about this opt-in animation technique</a> was part of the inspiration for writing a third article in this Un-Sass'ing series (they've since written a <a href="https://kilianvalkhof.com/2026/css-html/progressive-enhancement-as-a-benefit-of-css-nesting/">longer article</a> on it too).</p>
<p>It's also a great practical example of where nesting can genuinely earn its keep, handling user preferences like <code>prefers-reduced-motion</code> by keeping overrides grouped with the component. The example below uses an opt-in approach. Rather than adding a transition and then removing it for users who prefer reduced motion, we only add the transition when motion is acceptable.</p>
<p>No animation is the default.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--notification-bg</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--notification-color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
  <span class="token property">--notification-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--notification-radius</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--notification-position</span><span class="token punctuation">:</span> fixed<span class="token punctuation">;</span>
  <span class="token property">--notification-top</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--notification-right</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--notification-transform-start</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>400px<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--notification-transform-end</span><span class="token punctuation">:</span> <span class="token function">translateX</span><span class="token punctuation">(</span>0<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--notification-transition-duration</span><span class="token punctuation">:</span> 0.3s<span class="token punctuation">;</span>
  <span class="token property">--notification-transition-easing</span><span class="token punctuation">:</span> ease-out<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.notification</span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-position<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-top<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">right</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-right<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-transform-start<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token selector">&amp;.is-visible</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--notification-transform-end<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-reduced-motion</span><span class="token punctuation">:</span> no-preference<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">transition</span><span class="token punctuation">:</span> transform <span class="token function">var</span><span class="token punctuation">(</span>--notification-transition-duration<span class="token punctuation">)</span>
      <span class="token function">var</span><span class="token punctuation">(</span>--notification-transition-easing<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="CSS Nesting - Prefers Reduced Motion" src="https://codepen.io/sturobson/embed/yyaJpXg/bdeea5b34679615cc028debc9170f901?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/yyaJpXg/bdeea5b34679615cc028debc9170f901">
  CSS Nesting - Prefers Reduced Motion</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>Everything related to the notification's behaviour lives in one place, and motion is treated as a progressive enhancement rather than something you would have to remember to turn off.</p>
<h3 id="theming-with-data-attributes" tabindex="-1">Theming with Data Attributes</h3>
<p>Nesting keeps theme variations organised alongside your base styles. Custom properties make theming even more powerful by letting you define theme tokens that can be swapped out:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--prose-color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span>
  <span class="token property">--prose-bg</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  <span class="token property">--prose-padding</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token property">--prose-link-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--prose-link-hover</span><span class="token punctuation">:</span> #0056b3<span class="token punctuation">;</span>
  <span class="token property">--prose-code-bg</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>
  <span class="token property">--prose-code-padding</span><span class="token punctuation">:</span> 0.125rem 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--prose-code-radius</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--prose-dark-color</span><span class="token punctuation">:</span> #e0e0e0<span class="token punctuation">;</span>
  <span class="token property">--prose-dark-bg</span><span class="token punctuation">:</span> #1a1a1a<span class="token punctuation">;</span>
  <span class="token property">--prose-dark-link</span><span class="token punctuation">:</span> #4dabf7<span class="token punctuation">;</span>
  <span class="token property">--prose-dark-link-hover</span><span class="token punctuation">:</span> #74c0fc<span class="token punctuation">;</span>
  <span class="token property">--prose-dark-code-bg</span><span class="token punctuation">:</span> #2a2a2a<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.prose</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token selector">a</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-link-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>

    <span class="token selector">&amp;:hover</span> <span class="token punctuation">{</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-link-hover<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token selector">code</span> <span class="token punctuation">{</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-code-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-code-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-code-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">[data-theme='dark'] &amp;</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-dark-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-dark-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token selector">a</span> <span class="token punctuation">{</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-dark-link<span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token selector">&amp;:hover</span> <span class="token punctuation">{</span>
        <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-dark-link-hover<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token selector">code</span> <span class="token punctuation">{</span>
      <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--prose-dark-code-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="CSS Nesting - Mode/Theme Toggle" src="https://codepen.io/sturobson/embed/WbGxdEr/3194c41048487c2f3b0ced94c89b9c3d?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/WbGxdEr/3194c41048487c2f3b0ced94c89b9c3d">
  CSS Nesting - Mode/Theme Toggle</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>You can see at a glance how each element adapts to dark mode rather than hunting through separate rule blocks.</p>
<h3 id="interactive-states-with-%3Afocus-within" tabindex="-1">Interactive States with :focus-within</h3>
<p>Nesting makes complex interactive patterns much clearer.</p>
<p>Nesting and custom properties help maintain consistency across interactive elements.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--search-border</span><span class="token punctuation">:</span> 2px solid transparent<span class="token punctuation">;</span>
  <span class="token property">--search-border-focus</span><span class="token punctuation">:</span> 2px solid #007bff<span class="token punctuation">;</span>
  <span class="token property">--search-radius</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--search-bg</span><span class="token punctuation">:</span> #f5f5f5<span class="token punctuation">;</span>
  <span class="token property">--search-bg-focus</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
  <span class="token property">--search-padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--search-transition</span><span class="token punctuation">:</span> border-color 0.2s<span class="token punctuation">;</span>
  <span class="token property">--search-icon-color</span><span class="token punctuation">:</span> #666<span class="token punctuation">;</span>
  <span class="token property">--search-icon-focus</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--search-button-opacity</span><span class="token punctuation">:</span> 0.5<span class="token punctuation">;</span>
  <span class="token property">--search-button-visible</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
  <span class="token property">--search-button-transition</span><span class="token punctuation">:</span> opacity 0.2s<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.search-form</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> flex<span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-border<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-bg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">transition</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-transition<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token selector">&amp;:focus-within</span> <span class="token punctuation">{</span>
    <span class="token property">border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-border-focus<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-bg-focus<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token selector">.search-icon</span> <span class="token punctuation">{</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-icon-focus<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token selector">.search-button</span> <span class="token punctuation">{</span>
      <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-button-visible<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token property">pointer-events</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp; input</span> <span class="token punctuation">{</span>
    <span class="token property">border</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> transparent<span class="token punctuation">;</span>
    <span class="token property">flex</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
    <span class="token property">outline</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">.search-icon</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-icon-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">transition</span><span class="token punctuation">:</span> color 0.2s<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">.search-button</span> <span class="token punctuation">{</span>
    <span class="token property">opacity</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-button-opacity<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">pointer-events</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
    <span class="token property">transition</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--search-button-transition<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="css nesting - buttons" src="https://codepen.io/sturobson/embed/raMeexR/40121181eaa4c5eef54097114dbe83ad?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/raMeexR/40121181eaa4c5eef54097114dbe83ad">
  css nesting - buttons</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>When any child receives focus multiple coordinated style changes happen and you can see the entire interaction pattern in one block of CSS.</p>
<h3 id="modern-selector-patterns-with-%3Ahas()" tabindex="-1">Modern Selector Patterns with :has()</h3>
<p>The <code>:has()</code> selector combined with nesting unlocks powerful parent-child relationships:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.article</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>

  <span class="token selector">&amp;:has(> img)</span> <span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
    <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 200px 1fr<span class="token punctuation">;</span>
    <span class="token property">gap</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>

    <span class="token selector">img</span> <span class="token punctuation">{</span>
      <span class="token property">grid-row</span><span class="token punctuation">:</span> 1 / -1<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;:has(.quote)</span> <span class="token punctuation">{</span>
    <span class="token property">border-left</span><span class="token punctuation">:</span> 4px solid #007bff<span class="token punctuation">;</span>
    <span class="token property">padding-left</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token selector">&amp;:not(:has(h2))</span> <span class="token punctuation">{</span>
    <span class="token selector">&amp; p:first-of-type::first-letter</span> <span class="token punctuation">{</span>
      <span class="token property">font-size</span><span class="token punctuation">:</span> 3em<span class="token punctuation">;</span>
      <span class="token property">float</span><span class="token punctuation">:</span> left<span class="token punctuation">;</span>
      <span class="token property">margin-right</span><span class="token punctuation">:</span> 0.1em<span class="token punctuation">;</span>
      <span class="token property">line-height</span><span class="token punctuation">:</span> 0.9<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="400" style="width: 100%;" scrolling="no" title="CSS Nesting - :has" src="https://codepen.io/sturobson/embed/NPRrXXx/2953e2f426b03b6805d74114786a38b3?default-tab=css%2Cresult" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/NPRrXXx/2953e2f426b03b6805d74114786a38b3">
  CSS Nesting - :has</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>You're describing layout behaviour based on the content present. Nesting keeps these conditional patterns in one place and easily readable.</p>
<h2 id="when-to-nest-and-when-not-to" tabindex="-1">When to Nest and When Not To</h2>
<p>Nesting is really useful when you're adding behaviour or context to a selector, pseudo-classes, media query, or theme variants etc. If you're using BEM or similar methodologies, keep element selectors like <code>.button__icon</code> at the root level. The class name already describes the relationship, so nesting just adds specificity without adding clarity.</p>
<h3 id="nest-when" tabindex="-1">Nest when</h3>
<ul>
<li>Handling pseudo-classes, pseudo-elements, or state variations</li>
<li>Grouping media queries, container queries, or feature queries with their components</li>
<li>Handling user preferences like <code>prefers-reduced-motion</code> or <code>prefers-color-scheme</code></li>
<li>Creating theme variants or data-attribute patterns</li>
<li>The nesting improves readability without adding unnecessary specificity</li>
</ul>
<h3 id="avoid-nesting-when" tabindex="-1">Avoid nesting when</h3>
<ul>
<li>Using BEM or similar methodologies where classes are already specific</li>
<li>It would create overly specific selectors that are hard to override</li>
<li>Nesting more than 2-3 levels deep</li>
<li>Simply mirroring the DOM structure without adding value</li>
</ul>
<p>A simple rule I still follow from writing Sass for ~12 years – if you're nesting 3+ levels deep regularly, split it into smaller components. Although it's not a hard and fast rule, on occasion it can be broken.</p>
<h2 id="css-nesting-as-part-of-modern-css" tabindex="-1">CSS Nesting as Part of Modern CSS</h2>
<p>CSS nesting is one part of a larger &quot;Un-Sass'ing&quot; toolkit. Combined with CSS custom properties, <code>color-mix()</code>, and other modern features, nesting gives you a lot of what made Sass appealing without needing a preprocessor.</p>
<p>You lose some of the programmatic power of Sass (variables, mixins, functions) that gets compiled to 'simpler' CSS, but you gain the ability to write cleaner, more organised CSS that the browser understands natively.</p>
<p>The key is understanding when you're reaching for nesting and why. Use it where it makes sense and to keep your code organised, but don't let it become a shortcut that will create specificity problems down the line.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Beyond The Blur: A Quick Guide to the CSS Backdrop-Filter Property</title>
      <link href="https://www.alwaystwisted.com/articles/beyond-the-blur-css-backdrop-filter.html"/>
      <updated>2026-03-04T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/beyond-the-blur-css-backdrop-filter.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in 2019 I spotted a post from a Mozilla social media account announcing that <code>backdrop-filter</code> was implemented behind a flag in their Firefox Nightly build. I quickly threw together a <a href="https://codepen.io/sturobson/pen/eYOJMgN/e5979299c33348c312a4320c0f55d3dc">rough demo</a> and then a basic playground to explore what was possible.</p>
<p>Time passed and this last 6 months or so, with broader browser support and real-world usage in client projects, I've finally updated <a href="https://codepen.io/sturobson/pen/raMxdQz">that playground</a> to remove jQuery and modernise the code.</p>
<p>This quick article documents what <code>backdrop-filter</code> is, how it works, and how to use it effectively.</p>
<h2 id="what-is-backdrop-filter%3F" tabindex="-1">What is backdrop-filter?</h2>
<p>The <code>backdrop-filter</code> CSS property applies graphical effects such as blurring or colour shifting to the area behind an element. Unlike the standard <code>filter</code> property which affects the element itself, <code>backdrop-filter</code> only impacts what's behind it.</p>
<p>For the effect to be visible the element tends to need some kind of semi-transparent background, but this constraint could actually be useful as it can aid and enforce intentional design decisions rather than letting blur become a &quot;visual band-aid&quot;.</p>
<p>It could be particularly useful for creating &quot;glassmorphism&quot; effects - translucent overlays that slightly blur the content beneath (if you really, <em>really</em> felt the need).</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.frosted-glass</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 255<span class="token punctuation">,</span> 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">blur</span><span class="token punctuation">(</span>10px<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="why-backdrop-filter-is-useful" tabindex="-1">Why backdrop-filter is useful</h2>
<p><code>backdrop-filter</code> opens up design possibilities that would otherwise require heavier workarounds or compromises. Instead of choosing between obscuring content completely or losing visual focus, filters like blur create visual depth and separation with minimal overhead. Overlays and modals can maintain context—the visitor sees the page beneath and intuitively understands they're in a temporary state.</p>
<h2 id="backdrop-filter-options" tabindex="-1">Backdrop-filter options</h2>
<p>The <code>backdrop-filter</code> property accepts the same filter functions as the standard <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/filter"><code>filter</code> property</a>.</p>
<p>Here are the main options:</p>
<h3 id="blur()" tabindex="-1">blur()</h3>
<p>Applies a Gaussian blur to the backdrop. The value defines the blur radius in pixels.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">blur</span><span class="token punctuation">(</span>5px<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: blur" src="https://codepen.io/sturobson/embed/preview/yyaejvK?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/yyaejvK">
  backdrop-filter: blur</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="brightness()" tabindex="-1">brightness()</h3>
<p>Adjusts brightness. Values below 100% darken, above 100% brighten. Useful for softening bright backgrounds behind text.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">brightness</span><span class="token punctuation">(</span>150%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
  <iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: brightness" src="https://codepen.io/sturobson/embed/preview/PwGZeBb?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/PwGZeBb">
  backdrop-filter: brightness</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="contrast()" tabindex="-1">contrast()</h3>
<p>Adjusts the contrast. Below 100% reduces it, above 100% increases it.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">contrast</span><span class="token punctuation">(</span>200%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: contrast" src="https://codepen.io/sturobson/embed/preview/vEXLjzN?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/vEXLjzN">
  backdrop-filter: contrast</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="grayscale()" tabindex="-1">grayscale()</h3>
<p>Converts the background to greyscale. 100% removes all colour.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">grayscale</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: grayscale" src="https://codepen.io/sturobson/embed/preview/MYjKGZq?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/MYjKGZq">
  backdrop-filter: grayscale</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="hue-rotate()" tabindex="-1">hue-rotate()</h3>
<p>Rotates hues around the colour wheel. Values are set in degrees (<code>deg</code>).</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">hue-rotate</span><span class="token punctuation">(</span>180deg<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: hue-rotate" src="https://codepen.io/sturobson/embed/preview/QwKyrYQ?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/QwKyrYQ">
  backdrop-filter: hue-rotate</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="invert()" tabindex="-1">invert()</h3>
<p>Inverts colours completely. 100% is full inversion.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">invert</span><span class="token punctuation">(</span>75%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: invert" src="https://codepen.io/sturobson/embed/preview/YPGwLgw?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/YPGwLgw">
  backdrop-filter: invert</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="opacity()" tabindex="-1">opacity()</h3>
<p>Adjusts opacity of the backdrop. Lower = more transparent.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">opacity</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
  <iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: opacity" src="https://codepen.io/sturobson/embed/preview/ZYpQoPq?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/ZYpQoPq">
  backdrop-filter: opacity</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>Warning: <code>opacity()</code> has very limited browser support. It currently only seems to work in Firefox Nightly and ignores any other filter options in the rule (it ignores the <code>blue()</code> in the above example)</p>
</div></div>
<h3 id="saturate()" tabindex="-1">saturate()</h3>
<p>Adjusts colour saturation. Above 100% increases it, below decreases.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">saturate</span><span class="token punctuation">(</span>200%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: saturate" src="https://codepen.io/sturobson/embed/preview/WbGrJVM?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/WbGrJVM">
  backdrop-filter: saturate</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h3 id="sepia()" tabindex="-1">sepia()</h3>
<p>Applies a sepia tone. 100% is full sepia.</p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">sepia</span><span class="token punctuation">(</span>90%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: sepia" src="https://codepen.io/sturobson/embed/preview/JoRGZPj?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/JoRGZPj">
  backdrop-filter: sepia</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h2 id="combining-multiple-filters" tabindex="-1">Combining multiple filters</h2>
<p>You can stack multiple effects in a single <code>backdrop-filter</code> rule. Blur paired with brightness feels natural:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.glass-overlay</span> <span class="token punctuation">{</span>
  <span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">blur</span><span class="token punctuation">(</span>10px<span class="token punctuation">)</span> <span class="token function">brightness</span><span class="token punctuation">(</span>120%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: glass overlay" src="https://codepen.io/sturobson/embed/preview/bNwEKqM?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/bNwEKqM">
  backdrop-filter: glass overlay</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>But here's the catch: the order you list them in actually changes the result. Filters are applied sequentially, left to right, and each one operates on the output of the previous filter. When color-based filters interact (brightness, contrast, hue-rotate, saturate), the difference becomes visually obvious.</p>
<h2 id="filter-application-order" tabindex="-1">Filter application order</h2>
<p>Compare these two—same filters, different order:</p>
<p><strong>Brightness first, then contrast:</strong></p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">brightness</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span> <span class="token function">contrast</span><span class="token punctuation">(</span>150%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: order 1" src="https://codepen.io/sturobson/embed/preview/NPRxBvK?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/NPRxBvK">
  backdrop-filter: order 1</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p><strong>Contrast first, then brightness:</strong></p>
<pre class="language-css"><code class="language-css"><span class="token property">backdrop-filter</span><span class="token punctuation">:</span> <span class="token function">contrast</span><span class="token punctuation">(</span>150%<span class="token punctuation">)</span> <span class="token function">brightness</span><span class="token punctuation">(</span>50%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-g-feature">
<iframe height="300" style="width: 100%;" scrolling="no" title="backdrop-filter: order 2" src="https://codepen.io/sturobson/embed/preview/GgjoBvP?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/GgjoBvP">
  backdrop-filter: order 2</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>The first one darkens the backdrop, <em>then</em> applies extreme contrast to those darker values. The second applies contrast to the original colors first, <em>then</em> darkens the result. Blur and spatial effects are less sensitive to order, but always test your combinations to ensure they match your intent.</p>
<h2 id="browser-support" tabindex="-1">Browser support</h2>
<p><code>Backdrop-filter</code> is well supported across modern browsers. Chrome, Edge, Safari, and Firefox all support it.</p>
<p>The vast majority of filter functions work consistently: <code>blur()</code>, <code>brightness()</code>, <code>contrast()</code>, <code>grayscale()</code>, <code>hue-rotate()</code>, <code>invert()</code>, and <code>saturate()</code> are all broadly compatible. Where things get tricky is the newer or more experimental filters that some browsers haven't fully implemented yet.</p>
<p><code>opacity()</code> and <code>drop-shadow()</code> are the two filters that seem to, currently, have some significant limitations. As of this writing, <code>opacity()</code> only has reliable support in Firefox Nightly; it's ignored in Chrome, Edge, and Safari. Similarly, <code>drop-shadow()</code> currently only works in Firefox Nightly and looks to be unsupported elsewhere. If you need these effects, they're safe to use as progressively enhanced features, but don't rely on them as core functionality.</p>
<p>For robust support for colour and blur-based effects, stick with the filters that have universal adoption: <code>blur()</code> paired with <code>brightness()</code>, <code>contrast()</code>, or <code>grayscale()</code> gives you everything you need for glassmorphism effects without compatibility worry.</p>
<h2 id="wrapping-up" tabindex="-1">Wrapping up</h2>
<p><code>Backdrop-filter</code> is a pretty straightforward property. Pair it with a semi-transparent background, pick your filter(s) (blur is most useful), and test on real devices. The main trick is remembering that transparency is generally required for the effect to show.</p>
<h3 id="try-it-yourself" tabindex="-1">Try it yourself</h3>
<p>Play with all backdrop-filter options live in this CodePen—adjust blur, brightness, contrast, saturation, and more to see how they combine:</p>
<div class="at-g-feature">
<iframe height="600" style="width: 100%;" scrolling="no" title="Beyond The Blur - a backdrop-filter demo" src="https://codepen.io/sturobson/embed/raMxdQz/04ad816b434c583c27f2322243e64f24?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/raMxdQz/04ad816b434c583c27f2322243e64f24">
  Beyond The Blur - a backdrop-filter demo</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 15) - Managing Microcopy with Design Tokens and Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-15.html"/>
      <updated>2026-03-03T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-15.html</id>
      <content type="html">
        <![CDATA[
        <p>When we talk about design tokens, we usually mean colours, spacing, typography, and other visual properties. But there's another layer of design that's critical and rarely managed systematically: microcopy.</p>
<p>Microcopy is the small pieces of text scattered throughout your interface: button labels, form hints, error messages, empty states, confirmation dialogs. While we version control colour palettes and spacing scales, interface copy is commonly hardcoded into components, scattered across files, and inconsistently managed across platforms.</p>
<p>I was first introduced to microcopy in web design by <a href="https://www.linkedin.com/in/relly-annett-baker/">Relly</a>, and later during a workshop <a href="https://www.jina.me">Jina</a> ran in 2019, they mentioned how tokens could be a perfect fit for managing microcopy systematically.</p>
<p>These aren't mere strings. An error message that says &quot;Error&quot; versus &quot;Please enter a valid email address&quot; is a deliberate design decision affecting comprehension, trust, and conversion. A button labelled &quot;OK&quot; versus &quot;Save changes&quot; guides user behavior. If you want to follow along with a working example whilst reading this article, the <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/15-microcopy-tokens">Style Dictionary Starter includes a complete microcopy setup</a> you can explore and experiment with.</p>
<p>The problem is there could be no single source of truth. You can't say &quot;all our primary action buttons should say 'Continue'&quot; without hunting through dozens of files. When you need to update an error message, you would be hunting through codebases rather than updating a token. Designers, copywriters, and product managers can't propose changes without potentially diving into code or visiting every screen to be sure.</p>
<p>But, what if we could manage microcopy the same way we manage colours, spacing, and typography?</p>
<h2 id="why-manage-microcopy-as-tokens%3F" tabindex="-1">Why Manage Microcopy as Tokens?</h2>
<p>Managing microcopy in this way can give us several benefits.</p>
<p>First, you get consistency across your entire product. The language doesn't shift from &quot;Save&quot; in one place to &quot;Submit&quot; in another. Accessibility becomes part of the design by default: labels, aria-labels, and descriptions all defined in one place.</p>
<p>For teams supporting multiple languages, localisation becomes straightforward. Instead of managing separate systems with different schemas, you maintain a single token structure with language specific layers. Edit the JSON, rebuild, deploy.</p>
<p>Your product's brand voice comes through consistently across the entire interface, while team collaboration improves because everyone can participate. Every change can flow through git. You can roll back instantly, see who changed what and why, and maintain a complete trail.</p>
<p>Finally, you generate platform specific output from one source. JavaScript objects for web, Swift dictionaries for iOS, XML for Android. One source of truth for every platform.</p>
<h2 id="understanding-the-w3c-specification" tabindex="-1">Understanding the W3C Specification</h2>
<p>Here's where it gets a little interesting.</p>
<p>The W3C Design Tokens Community Group specification doesn't currently include a <code>content</code> or <code>string</code> type. The spec defines:</p>
<h3 id="basic-types" tabindex="-1">Basic types</h3>
<ul>
<li><code>color</code></li>
<li><code>dimension</code></li>
<li><code>fontFamily</code></li>
<li><code>fontWeight</code></li>
<li><code>duration</code></li>
<li><code>cubicBezier</code></li>
<li><code>number</code></li>
</ul>
<h3 id="composite-types" tabindex="-1">Composite types</h3>
<ul>
<li><code>strokeStyle</code></li>
<li><code>border</code></li>
<li><code>transition</code></li>
<li><code>shadow</code></li>
<li><code>gradient</code></li>
<li><code>typography</code></li>
</ul>
<p>No <code>content</code>. No <code>string</code>.</p>
<p>Since every token must have a valid <code>$type</code>, we have a specification gap.</p>
<p>How can we add microcopy? We will have to work around this.</p>
<p>We can either inherit a <code>$type</code> from a parent group or acknowledge we're extending the spec beyond what it currently supports. The best practice is to set <code>$type</code> at the group level, your microcopy group can declare a type, and then use <code>$extensions</code> to mark which tokens are actually microcopy.</p>
<p>Remember the article on <a href="https://www.alwaystwisted.com/articles/understanding-extensions-in-the-design-tokens-spec">Understanding $extensions in the Design Tokens Specification</a>?</p>
<p>This is exactly what it's designed for. Adding custom, tool-specific data without breaking the standard. Microcopy is a perfect use case.</p>
<h2 id="structuring-microcopy-tokens" tabindex="-1">Structuring Microcopy Tokens</h2>
<p>A well organised microcopy token structure mirrors how developers think about interfaces. Group content by context (forms, navigation, feedback) and component type (button, input, modal), using the same hierarchical approach you'd apply to colours or spacing.</p>
<p>I recommend something like this structure:</p>
<pre><code>tokens/
  copy.tokens.json         # Root file with group-level $type
  copy-button.tokens.json  # Button labels
  copy-form.tokens.json    # Form labels, hints, placeholders
  copy-error.tokens.json   # Validation, system, and UI state messages
</code></pre>
<p>This keeps all token files in the same <code>tokens/</code> folder for simplicity. The root file establishes the group structure, while category files contain the actual token definitions.</p>
<h2 id="creating-microcopy-tokens-with-%24extensions" tabindex="-1">Creating Microcopy Tokens With <code>$extensions</code></h2>
<p>The spec requires every token to have a valid <code>$type</code>. Since there's no <code>string</code> type, we set <code>$type</code> at the group level (using a placeholder type like <code>number</code>) and rely on <code>$extensions</code> to identify microcopy tokens. This is a pragmatic workaround to an acknowledged gap in the spec.</p>
<p>Start by creating the root token file <code>tokens/copy.tokens.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span>
    <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Microcopy tokens. Type is set here to satisfy spec requirements; use $extensions to identify actual microcopy tokens."</span><span class="token punctuation">,</span>
    <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"form"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"error"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This root file serves as the group-level container for all microcopy tokens. By setting <code>$type</code> at the top level, all child tokens inherit this type, eliminating the need to repeat <code>$type</code> in every individual <code>tokens.json</code> file. The empty objects (<code>&quot;button&quot;: {}</code>, etc.) define the structure without containing actual token values.</p>
<p>Now create button labels in <code>tokens/copy-button.tokens.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Continue"</span><span class="token punctuation">,</span>
          <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary action button label"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
              <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"button"</span><span class="token punctuation">,</span>
              <span class="token property">"context"</span><span class="token operator">:</span> <span class="token string">"primary-action"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Cancel"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
              <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"button"</span><span class="token punctuation">,</span>
              <span class="token property">"context"</span><span class="token operator">:</span> <span class="token string">"secondary-action"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"submit"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Submit"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
              <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"button"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"delete"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Delete"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
              <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"button"</span><span class="token punctuation">,</span>
              <span class="token property">"context"</span><span class="token operator">:</span> <span class="token string">"destructive"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"confirm"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Are you sure you want to delete this item?"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
              <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"button"</span><span class="token punctuation">,</span>
              <span class="token property">"context"</span><span class="token operator">:</span> <span class="token string">"destructive-confirm"</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Now form related copy in <code>tokens/copy-form.tokens.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"form"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"input"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"email"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Email address"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token property">"placeholder"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"you@example.com"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token property">"hint"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"We'll never share your email with anyone else"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"password"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Password"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token property">"placeholder"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Enter your password"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token property">"hint"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Must be at least 8 characters"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Error and UI state messages in <code>tokens/copy-error.tokens.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"error"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"validation"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"required"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"This field is required"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"email"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"invalid"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Please enter a valid email address"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"password"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"tooShort"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Password must be at least 8 characters"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token property">"mismatch"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Passwords do not match"</span><span class="token punctuation">,</span>
            <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="generating-microcopy-with-style-dictionary" tabindex="-1">Generating Microcopy With Style Dictionary</h2>
<p>Now that we have our tokens structured with <code>$extensions</code>, we need to get them into our build pipeline. We'll create custom Style Dictionary formats that output JavaScript and JSON from the same source.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>Since the DTCG spec doesn't define a string type, we used <code>$type: number</code> as a placeholder at the group level in our token definitions. This allows tokens to be valid according to the spec while we use <code>$extensions</code> to identify actual microcopy. The key is that Style Dictionary can filter based on the extension, which is what matters for our build.</p>
</div></div>
<p>Create a <code>build.js</code> file to build your microcopy tokens:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Filter tokens to get only microcopy tokens based on extensions</span>
<span class="token keyword">const</span> <span class="token function-variable function">getMicrocopyTokens</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">dictionary</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">(</span>
      token<span class="token punctuation">.</span>$extensions <span class="token operator">&amp;&amp;</span>
      token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.alwaystwisted.microcopy'</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span>
      token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.alwaystwisted.microcopy'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>enabled
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Build a nested object from flat token paths</span>
<span class="token keyword">const</span> <span class="token function-variable function">buildNestedObject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

  tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> path <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Skip 'copy' prefix from path</span>
    <span class="token keyword">let</span> current <span class="token operator">=</span> result<span class="token punctuation">;</span>

    path<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">===</span> path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Set the value at the final key</span>
        current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token comment">// Create nested object if it doesn't exist</span>
        current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
        current <span class="token operator">=</span> current<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for JavaScript ES6 export</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'javascript/microcopy'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> nested <span class="token operator">=</span> <span class="token function">buildNestedObject</span><span class="token punctuation">(</span><span class="token function">getMicrocopyTokens</span><span class="token punctuation">(</span>dictionary<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">export const microcopy = </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>nested<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for JSON output</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'json/microcopy'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> nested <span class="token operator">=</span> <span class="token function">buildNestedObject</span><span class="token punctuation">(</span><span class="token function">getMicrocopyTokens</span><span class="token punctuation">(</span>dictionary<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>nested<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.tokens.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// Source files for tokens</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">js</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span> <span class="token comment">// Use JavaScript transforms</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/js/'</span><span class="token punctuation">,</span> <span class="token comment">// Output directory</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'microcopy.js'</span><span class="token punctuation">,</span> <span class="token comment">// Output file</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/microcopy'</span><span class="token punctuation">,</span> <span class="token comment">// Use custom format</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">json</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/json/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'microcopy.json'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'json/microcopy'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> sd<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Run the build with <code>node build.js</code> and you'll get:</p>
<pre><code>build/
  js/
    microcopy.js
  json/
    microcopy.json
</code></pre>
<p>For example, <code>build/js/microcopy.js</code> gives you a nested object:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> microcopy <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">button</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">primary</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Continue'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">secondary</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Cancel'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">submit</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Submit'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token keyword">delete</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">label</span><span class="token operator">:</span> <span class="token string">'Delete'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">confirm</span><span class="token operator">:</span> <span class="token string">'Are you sure you want to delete this item?'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// ... ,,,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2 id="using-microcopy-tokens-in-components" tabindex="-1">Using Microcopy Tokens in Components</h2>
<p>Now you can use this in your components with clean, semantic references.</p>
<h3 id="react-example" tabindex="-1">React Example</h3>
<p>Here's a simple sign-up form demonstrating microcopy token usage:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> microcopy <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./build/js/microcopy.js'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">SignUpForm</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// State for form input</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>email<span class="token punctuation">,</span> setEmail<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>form</span><span class="token punctuation">></span></span><span class="token plain-text">
      </span><span class="token punctuation">{</span><span class="token comment">/* Email input using microcopy tokens for label and placeholder */</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>form-group<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>label</span> <span class="token attr-name">htmlFor</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>microcopy<span class="token punctuation">.</span>form<span class="token punctuation">.</span>input<span class="token punctuation">.</span>email<span class="token punctuation">.</span>label<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>label</span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span>
          <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
          <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span>
          <span class="token attr-name">placeholder</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>microcopy<span class="token punctuation">.</span>form<span class="token punctuation">.</span>input<span class="token punctuation">.</span>email<span class="token punctuation">.</span>placeholder<span class="token punctuation">}</span></span>
          <span class="token attr-name">value</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>email<span class="token punctuation">}</span></span>
          <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">}</span></span>
        <span class="token punctuation">/></span></span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span class="token plain-text">

      </span><span class="token punctuation">{</span><span class="token comment">/* Submit button using microcopy token for text */</span><span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>submit<span class="token punctuation">"</span></span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn-primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text">
        </span><span class="token punctuation">{</span>microcopy<span class="token punctuation">.</span>button<span class="token punctuation">.</span>submit<span class="token punctuation">.</span>label<span class="token punctuation">}</span><span class="token plain-text">
      </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span><span class="token plain-text">
    </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>form</span><span class="token punctuation">></span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This is far more readable than hardcoded strings. Instead of <code>&lt;button&gt;Submit&lt;/button&gt;</code>, you have a semantic reference that clearly identifies which piece of text you're using. When a copywriter updates the token, every instance updates automatically.</p>
<h3 id="vanilla-javascript-validation" tabindex="-1">Vanilla JavaScript Validation</h3>
<p>Here's a simple validation function using microcopy:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> microcopy <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./build/js/microcopy.js'</span><span class="token punctuation">;</span>

<span class="token comment">// Validate email with microcopy messages</span>
<span class="token keyword">function</span> <span class="token function">validateEmail</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>value <span class="token operator">||</span> value<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">valid</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> microcopy<span class="token punctuation">.</span>error<span class="token punctuation">.</span>validation<span class="token punctuation">.</span>required <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">const</span> emailRegex <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^[^\s@]+@[^\s@]+\.[^\s@]+$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>emailRegex<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">valid</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">message</span><span class="token operator">:</span> microcopy<span class="token punctuation">.</span>error<span class="token punctuation">.</span>validation<span class="token punctuation">.</span>email<span class="token punctuation">.</span>invalid <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">valid</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Usage</span>
<span class="token keyword">const</span> emailInput <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'#email'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> errorElement <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'.error-message'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

emailInput<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'blur'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">validateEmail</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  errorElement<span class="token punctuation">.</span>textContent <span class="token operator">=</span> result<span class="token punctuation">.</span>valid <span class="token operator">?</span> <span class="token string">''</span> <span class="token operator">:</span> result<span class="token punctuation">.</span>message<span class="token punctuation">;</span>
  errorElement<span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> result<span class="token punctuation">.</span>valid <span class="token operator">?</span> <span class="token string">'none'</span> <span class="token operator">:</span> <span class="token string">'block'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The validator is completely decoupled from actual messages. Update the tokens, rebuild, and validation messages update everywhere automatically.</p>
<h2 id="multi-language-support-through-token-layers" tabindex="-1">Multi-Language Support Through Token Layers</h2>
<p>Design tokens really shine for internationalization. Instead of managing separate i18n files with different structures, use the same token architecture you use for theming.</p>
<p>Create language-specific token files. Set <code>$type</code> at the group level (using our placeholder approach), then override the values:</p>
<p><strong><code>tokens/copy-en-button.tokens.json</code></strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Continue"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Cancel"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong><code>tokens/copy-fr-button.tokens.json</code></strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"copy"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Continuer"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"label"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Annuler"</span><span class="token punctuation">,</span>
          <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"com.alwaystwisted.microcopy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"enabled"</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Create a <code>build-i18n.js</code> file for multi-language builds:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for JavaScript ES6 export (multi-language version)</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'javascript/microcopy'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// Filter to get only microcopy tokens</span>
    <span class="token keyword">const</span> microcopyTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">(</span>
        token<span class="token punctuation">.</span>$extensions <span class="token operator">&amp;&amp;</span>
        token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.alwaystwisted.microcopy'</span><span class="token punctuation">]</span> <span class="token operator">&amp;&amp;</span>
        token<span class="token punctuation">.</span>$extensions<span class="token punctuation">[</span><span class="token string">'com.alwaystwisted.microcopy'</span><span class="token punctuation">]</span><span class="token punctuation">.</span>enabled
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// Build nested object from token paths</span>
    <span class="token keyword">const</span> <span class="token function-variable function">buildNestedObject</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
      tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> path <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Skip 'copy' prefix</span>
        <span class="token keyword">let</span> current <span class="token operator">=</span> result<span class="token punctuation">;</span>
        path<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">key<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">===</span> path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">;</span>
          <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> current<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
            current <span class="token operator">=</span> current<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> nested <span class="token operator">=</span> <span class="token function">buildNestedObject</span><span class="token punctuation">(</span>microcopyTokens<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">export const microcopy = </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>nested<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// List of supported languages</span>
<span class="token keyword">const</span> languages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token string">'fr'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">// Build microcopy for each language</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> language <span class="token keyword">of</span> languages<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">tokens/copy-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>language<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-*.tokens.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// Language-specific token files</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">js</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">build/js/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>language<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// Output to language-specific directory</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'microcopy.js'</span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/microcopy'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span>config<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">await</span> sd<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Run the multi-language build with <code>node build-i18n.js</code>.</p>
<p>This creates:</p>
<pre><code>build/
  js/
    en/microcopy.js
    fr/microcopy.js
</code></pre>
<p>With identical structure, just different copy.</p>
<h2 id="why-this-approach-works" tabindex="-1">Why This Approach Works</h2>
<p>Using <code>$extensions</code> for microcopy keeps your tokens valid according to the DTCG spec. Other tools can parse your files without breaking, even if they don't understand your extensions. When the spec evolves, the DTCG is actively discussing it, so you can migrate seamlessly.</p>
<p>More importantly, it treats microcopy as a first-class citizen in your design system. It's not an afterthought. It's not a hack. It's part of your core token infrastructure, managed the same way you manage colours, spacing, and typography. For a complete working implementation, refer to the <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/15-microcopy-tokens">Style Dictionary Starter repository</a>.</p>
<p>Your interface copy directly impacts how users understand, trust, and succeed with your product. It deserves systematic management, version control, collaboration, and the same attention you give to visual design.</p>
<p>Start small. Tokenise your error messages. Then expand. You'll wonder how you ever managed microcopy any other way.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Building Fluid Typographic Scales with clamp() and :heading()</title>
      <link href="https://www.alwaystwisted.com/articles/building-fluid-typographic-scales-with-clamp-and-heading.html"/>
      <updated>2026-02-19T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/building-fluid-typographic-scales-with-clamp-and-heading.html</id>
      <content type="html">
        <![CDATA[
        <p>In the last article, I showed how to use explicit <code>:heading(N)</code> level mapping with <code>pow()</code> to create mathematical typographic scales. This article extends that approach to fluid scaling with <code>clamp()</code>, so your heading sizes adapt smoothly to the viewport instead of jumping at breakpoints.</p>
<h2 id="the-fluid-typography-formula" tabindex="-1">The Fluid Typography Formula</h2>
<p>Fluid typography scales smoothly with the viewport instead of jumping at breakpoints. With <code>clamp()</code>, you define a minimum size, a maximum size, and the viewport boundaries—the maths calculates the scaling automatically, keeping text within those bounds.</p>
<p>The underlying formula is a linear ramp between your minimum and maximum viewport widths:</p>
<pre class="language-css"><code class="language-css"><span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">clamp</span><span class="token punctuation">(</span>
  min-size<span class="token punctuation">,</span>
  min-size + <span class="token punctuation">(</span>max-size - min-size<span class="token punctuation">)</span> *
    <span class="token punctuation">(</span><span class="token punctuation">(</span>100vw - min-viewport<span class="token punctuation">)</span> / <span class="token punctuation">(</span>max-viewport - min-viewport<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  max-size
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Where:</p>
<ul>
<li><strong>min-size</strong>: Smallest font size (e.g., 1rem)</li>
<li><strong>max-size</strong>: Largest font size (e.g., 2rem)</li>
<li><strong>min-viewport</strong>: Viewport width where scaling starts (e.g., 375px)</li>
<li><strong>max-viewport</strong>: Viewport width where scaling stops (e.g., 1440px)</li>
</ul>
<p>You can calculate these values by hand, or use tools like <a href="https://utopia.fyi">Utopia</a>, <a href="https://www.fluidtypography.com">Fluid Typography</a>, or <a href="https://typefluidity.com">Type Fluidity</a> to experiment with different ratios and sizes before implementing.</p>
<h2 id="implementing-with-%3Aheading()" tabindex="-1">Implementing with :heading()</h2>
<p>The <code>:heading()</code> pseudo-class lets you write the sizing logic once in a single <code>:heading</code> rule, then map each heading level to a number. Compare that to writing separate font-size calculations for h1, h2, h3, h4, h5, h6.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Why explicit level mapping:</strong> <code>:heading(N) { --heading-level: X; }</code> stays reliable regardless of your HTML structure—h1 stays h1 even with repeated or skipped heading levels.</p>
</div></div>
<p>By writing the sizing logic in one <code>:heading</code> block, all the maths lives in a single place. To change how the scale works, you edit one place instead of duplicating calculations across h1, h2, h3, h4, h5, h6.</p>
<p>The level mapping is simple, <code>:heading(1) { --heading-level: 5; }</code> is a one-liner. You set a number rather than writing the entire clamp() calculation for each heading.</p>
<p>Because you're explicitly mapping <code>:heading(N)</code> to <code>--heading-level</code> values, your headings size correctly regardless of HTML structure. h3 stays h3 even if your markup has repeated heading levels.</p>
<p>Finally, it's design system friendly. Change the <code>:root</code> variables once, and every heading updates instantly across your entire project.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Why h1 = level 5, not 1 or 6?</strong> The maths works with exponents. An exponent of 0 gives you the base size: h6 = 1rem × 1.2^0 = 1rem. Counting up from 0 means h1's larger exponent (5) naturally produces a larger size: 1rem × 1.2^5 ≈ 2.49rem. If we started h1 at 1, the scale would be inverted. If we started at 6, h6 would be 1rem × 1.2^6, not the base size.</p>
</div></div>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Viewport boundaries for fluid scaling */</span>
  <span class="token property">--fluid-min</span><span class="token punctuation">:</span> 375px<span class="token punctuation">;</span> <span class="token comment">/* where scaling starts */</span>
  <span class="token property">--fluid-max</span><span class="token punctuation">:</span> 1440px<span class="token punctuation">;</span> <span class="token comment">/* where scaling stops */</span>
  <span class="token property">--fluid-range</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--fluid-max<span class="token punctuation">)</span> - <span class="token function">var</span><span class="token punctuation">(</span>--fluid-min<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Base font size: min at 375px viewport, max at 1440px */</span>
  <span class="token property">--base-min</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--base-max</span><span class="token punctuation">:</span> 1.125rem<span class="token punctuation">;</span>

  <span class="token comment">/* Musical scale ratios (pick one by changing --scale-min and --scale-max) */</span>
  <span class="token property">--scale-minor-second</span><span class="token punctuation">:</span> 1.067<span class="token punctuation">;</span>
  <span class="token property">--scale-major-second</span><span class="token punctuation">:</span> 1.125<span class="token punctuation">;</span>
  <span class="token property">--scale-minor-third</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">--scale-major-third</span><span class="token punctuation">:</span> 1.25<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fourth</span><span class="token punctuation">:</span> 1.333<span class="token punctuation">;</span>
  <span class="token property">--scale-augmented-fourth</span><span class="token punctuation">:</span> 1.414<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fifth</span><span class="token punctuation">:</span> 1.5<span class="token punctuation">;</span>
  <span class="token property">--scale-golden-ratio</span><span class="token punctuation">:</span> 1.618<span class="token punctuation">;</span>

  <span class="token comment">/* Set your scales here */</span>
  <span class="token property">--scale-min</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-minor-third<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--scale-max</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-perfect-fourth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">--exponent</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-level<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Calculate min and max sizes for this heading level */</span>
  <span class="token property">--size-min</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--base-min<span class="token punctuation">)</span> * <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--scale-min<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--exponent<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--size-max</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--base-max<span class="token punctuation">)</span> * <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--scale-max<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--exponent<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Linear ramp: (max - min) / viewport-range scaled to 100vw */</span>
  <span class="token property">--fluid-rate</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--size-max<span class="token punctuation">)</span> - <span class="token function">var</span><span class="token punctuation">(</span>--size-min<span class="token punctuation">)</span><span class="token punctuation">)</span> * 100 / <span class="token function">var</span><span class="token punctuation">(</span>--fluid-range<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">clamp</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--size-min<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--size-min<span class="token punctuation">)</span> + <span class="token function">var</span><span class="token punctuation">(</span>--fluid-rate<span class="token punctuation">)</span> * <span class="token punctuation">(</span>100vw - <span class="token function">var</span><span class="token punctuation">(</span>--fluid-min<span class="token punctuation">)</span><span class="token punctuation">)</span> / 100<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--size-max<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading(1)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 5<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(2)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 4<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(3)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(4)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(5)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(6)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Each heading level gets its own fluid rate because the size-range grows exponentially with the exponent. h1 scales more aggressively than h6, maintaining the typographic ratio across all viewport sizes.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Accessibility Note:</strong> This approach complies with WCAG 1.4.4 (Resize Text) because the <code>clamp()</code> min/max values use <code>rem</code> units, which scale with browser zoom. Viewport units only control the rate of change between viewport widths—they don't prevent zooming. Always use <code>rem</code> (never <code>px</code>) and test with browser zoom at different viewport widths.</p>
</div></div>
<h2 id="browser-support" tabindex="-1">Browser Support</h2>
<p><code>clamp()</code> has excellent support across all modern browsers (Chrome 79+, Firefox 75+, Safari 13.1+). The <code>:heading()</code> pseudo-class and <code>pow()</code> function are currently experimental and only available in Safari Technology Preview.</p>
<p>If you want to track progress or add support signals for the missing pieces:</p>
<ul>
<li><a href="https://issues.chromium.org/issues/438147580"><code>:heading</code> (Chrome)</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1953973"><code>:heading</code> (Firefox)</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1782527"><code>pow()</code> (Firefox)</a></li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Building Typographic Scales in CSS with :heading(), sibling-index(), and pow()</title>
      <link href="https://www.alwaystwisted.com/articles/building-typographic-scales-with-headings-sibling-index-and-pow.html"/>
      <updated>2026-02-17T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/building-typographic-scales-with-headings-sibling-index-and-pow.html</id>
      <content type="html">
        <![CDATA[
        <p>In <a href="https://www.alwaystwisted.com/articles/styling-with-the-heading-pseudo-class">my previous article</a>, I introduced the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:heading"><code>:heading</code> pseudo-class</a> and showed how it can simplify styling all headings in groups, or all at once. Today, I want to take that much further and show how combining <code>:heading()</code> with two other CSS features—<code>sibling-index()</code> and <code>pow()</code> lets us build flexible, maintainable typographic scales with just a few lines of code.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Important limitation:</strong> <code>sibling-index()</code> counts <em>siblings</em>, not heading levels. That means the scale only lines up if you have a clean, ordered run of <code>h1</code> → <code>h6</code>. If you repeat a heading level (for example: <code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h3</code>), the second <code>h3</code> will be sized like <code>h4</code> because its sibling index is higher. Keep that in mind if you use this pattern in real layouts.</p>
</div></div>
<p>There’s still a lot to like here, but the ordering limitation matters in real content.</p>
<p>If you want the version that works regardless of heading order, skip to <a href="#what-works-in-real-layouts">What Works in Real Layouts</a>.</p>
<h2 id="the-problem-with-traditional-typographic-scales" tabindex="-1">The Problem with Traditional Typographic Scales</h2>
<p>When you implement a typographic scale in CSS today, you may end up with something like this.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">h1</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 3.052rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">h2</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 2.441rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">h3</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.953rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">h4</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.563rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">h5</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">h6</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This works, but it's repetitive.</p>
<p>Separate declarations for what's essentially a mathematical pattern. It may be inflexible too. Want to try a different ratio? You'll need to recalculate all the values manually, which could be error prone when dealing with exponential calculations. The relationship between values isn't expressed in the code itself, which could make it harder to understand and maintain.</p>
<p>What we really want is to define the pattern once and let CSS calculate the individual values for us.</p>
<h2 id="understanding-typographic-scales" tabindex="-1">Understanding Typographic Scales</h2>
<p>Typographic scales use ratios (mostly) borrowed from musical intervals. These ratios create &quot;harmonious&quot; proportions because they're based on the same mathematical relationships that make good music feel right.</p>
<p>Common scales:</p>
<ul>
<li>Minor Third (1.200) - Subtle</li>
<li>Major Third (1.250) - Balanced</li>
<li>Perfect Fourth (1.333) - Slightly more dramatic</li>
<li>Perfect Fifth (1.500) - Bold</li>
<li>Golden Ratio (1.618) - Not a musical interval, but commonly used</li>
</ul>
<p>These scales are exponential, not linear. Each heading level multiplies the previous level by the ratio, rather than adding to it.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Exponential vs Linear:</strong> With a linear scale, each step adds the same fixed amount. With an exponential scale, each step multiplies by the ratio—so you get bigger jumps between larger sizes. That's why h1 is so much bigger than h2, which is bigger than h3, and so on, and so on, and so on.</p>
</div></div>
<p>Here's what that exponential growth looks like across heading levels with a Major Third scale (1.25):</p>
<pre><code>h6: 1rem × 1.25⁰ = 1rem
h5: 1rem × 1.25¹ = 1.25rem
h4: 1rem × 1.25² = 1.563rem
h3: 1rem × 1.25³ = 1.953rem
h2: 1rem × 1.25⁴ = 2.441rem
h1: 1rem × 1.25⁵ = 3.052rem
</code></pre>
<p>The pattern, base-size × ratio ^ exponent.</p>
<p>This is where <code>pow()</code> comes in.</p>
<h2 id="enter-pow()%3A-exponentiation-in-css" tabindex="-1">Enter pow(): Exponentiation in CSS</h2>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/pow"><code>pow()</code> function</a> is part of <a href="https://www.w3.org/TR/css-values-4/">CSS Values and Units Level 4</a>. It calculates a number raised to a power (<a href="https://en.wikipedia.org/wiki/Exponentiation">exponentiation</a>) in CSS.</p>
<pre class="language-css"><code class="language-css"><span class="token function">pow</span><span class="token punctuation">(</span>base<span class="token punctuation">,</span> exponent<span class="token punctuation">)</span></code></pre>
<p>For example:</p>
<ul>
<li><code>pow(2, 3) = 2³ = 8</code></li>
<li><code>pow(1.25, 4) = 1.25⁴ = 2.441</code></li>
</ul>
<p>This is exactly what we need to help calculate typographic scales. Instead of manually computing 1.25 × 1.25 × 1.25 × 1.25, we can write <code>pow(1.25, 4)</code>.</p>
<h2 id="the-missing-piece%3A-sibling-index()" tabindex="-1">The Missing Piece: sibling-index()</h2>
<p>Here's how it works in the ideal case. The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/sibling-index"><code>sibling-index()</code> function</a> returns the position of an element among its siblings, starting from 1 (it works with any elements, not just <code>:heading</code>).</p>
<p>In a typical demo where <code>h1</code> through <code>h6</code> are siblings in order, that index lines up with the heading level:</p>
<ul>
<li>h1 has <code>sibling-index() = 1</code></li>
<li>h2 has <code>sibling-index() = 2</code></li>
<li>h3 has <code>sibling-index() = 3</code></li>
<li>And so on...</li>
</ul>
<p>This means we can use <code>sibling-index()</code> to calculate the size dynamically for each heading level.</p>
<h2 id="putting-it-all-together" tabindex="-1">Putting It All Together</h2>
<p>Here's the full pattern in action:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--font-size-base</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--scale-major-third</span><span class="token punctuation">:</span> 1.25<span class="token punctuation">;</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-major-third<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--font-size-base<span class="token punctuation">)</span> * <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--typographic-scale<span class="token punctuation">)</span><span class="token punctuation">,</span> 6 - <span class="token function">sibling-index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>That's it. Three custom properties and one font-size rule.</p>
<p>Let's break down what's happening. First, <code>6 - sibling-index()</code> calculates the exponent for each heading. For h1 (index 1) it becomes <code>6 - 1 = 5</code>, for h2 it becomes <code>6 - 2 = 4</code>, and for h6 it becomes <code>6 - 6 = 0</code>.</p>
<p>Next, <code>pow(var(--typographic-scale), ...)</code> raises the scale ratio to that exponent. With a 1.25 ratio, h1 becomes <code>pow(1.25, 5) = 3.052</code>, h2 becomes <code>pow(1.25, 4) = 2.441</code>, and h6 becomes <code>pow(1.25, 0) = 1</code>.</p>
<p>Finally, <code>var(--font-size-base) * ...</code> multiplies that result by the base size so the whole scale can move up or down together.</p>
<p>The result is that h1 is the largest, h6 is the base size, and everything in between follows the exponential scale perfectly.</p>
<p>If you want a one-line mental model, it's this: <strong>font-size = base-size x ratio^(6 - sibling-index())</strong>. With a Perfect Fourth scale (1.333), that gives you a range from h1 at 4.209rem down to h6 at 1rem, with each heading level stepping down by the same ratio.</p>
<h2 id="building-a-complete-scale-system" tabindex="-1">Building a Complete Scale System</h2>
<p>Let's expand this into a practical system with multiple scale options:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Scale ratios based on musical intervals */</span>
  <span class="token property">--scale-minor-second</span><span class="token punctuation">:</span> 1.067<span class="token punctuation">;</span>
  <span class="token property">--scale-major-second</span><span class="token punctuation">:</span> 1.125<span class="token punctuation">;</span>
  <span class="token property">--scale-minor-third</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">--scale-major-third</span><span class="token punctuation">:</span> 1.25<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fourth</span><span class="token punctuation">:</span> 1.333<span class="token punctuation">;</span>
  <span class="token property">--scale-augmented-fourth</span><span class="token punctuation">:</span> 1.414<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fifth</span><span class="token punctuation">:</span> 1.5<span class="token punctuation">;</span>
  <span class="token property">--scale-golden-ratio</span><span class="token punctuation">:</span> 1.618<span class="token punctuation">;</span>

  <span class="token comment">/* Active scale - change this to switch globally */</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-major-third<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Base size and max level for clarity */</span>
  <span class="token property">--heading-base-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--heading-max-level</span><span class="token punctuation">:</span> 6<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--heading-base-size<span class="token punctuation">)</span> *
      <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--typographic-scale<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-max-level<span class="token punctuation">)</span> - <span class="token function">sibling-index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Now you can experiment with different scales by changing a single variable. Want to try a Perfect Fourth scale? Just update <code>--typographic-scale</code>:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-perfect-fourth<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Every heading on your site instantly updates to the new scale.</p>
<p>You can also nudge the overall size up or down by adjusting <code>--heading-base-size</code>.</p>
<h2 id="responsive-typography" tabindex="-1">Responsive Typography</h2>
<p>Several years ago I attended an amazing workshop from <a href="https://clagnut.com">Rich</a> on responsive web typography, and one thing stuck with me. You don't have to use the same scale across all devices. Narrow viewports can use a tighter scale, while larger viewports can breathe a little more. Using the system we've created, we can adjust the scale based on viewport size.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-minor-third<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Smaller scale on mobile to prevent oversized headings */</span>
<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width >= 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-major-third<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Larger scale on big screens where you have more space */</span>
<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width >= 1400px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-perfect-fourth<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="practical-example%3A-a-complete-design-system" tabindex="-1">Practical Example: A Complete Design System</h2>
<p>Here's how you might structure this in a real design system:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token comment">/* Color tokens */</span>
  <span class="token property">--color-heading</span><span class="token punctuation">:</span> #2c3e50<span class="token punctuation">;</span>
  <span class="token property">--color-heading-secondary</span><span class="token punctuation">:</span> #546e7a<span class="token punctuation">;</span>

  <span class="token comment">/* Typography scales */</span>
  <span class="token property">--scale-minor-third</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">--scale-major-third</span><span class="token punctuation">:</span> 1.25<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fourth</span><span class="token punctuation">:</span> 1.333<span class="token punctuation">;</span>
  <span class="token property">--scale-augmented-fourth</span><span class="token punctuation">:</span> 1.414<span class="token punctuation">;</span>
  <span class="token property">--scale-perfect-fifth</span><span class="token punctuation">:</span> 1.5<span class="token punctuation">;</span>
  <span class="token property">--scale-golden-ratio</span><span class="token punctuation">:</span> 1.618<span class="token punctuation">;</span>

  <span class="token comment">/* Active scale */</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-minor-third<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Base values */</span>
  <span class="token property">--heading-base-size</span><span class="token punctuation">:</span> 0.9375rem<span class="token punctuation">;</span>
  <span class="token property">--heading-max-level</span><span class="token punctuation">:</span> 6<span class="token punctuation">;</span>
  <span class="token property">--heading-font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">--heading-font-weight--strong</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
  <span class="token property">--heading-line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing</span><span class="token punctuation">:</span> -0.02em<span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing--tight</span><span class="token punctuation">:</span> -0.03em<span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing--loose</span><span class="token punctuation">:</span> -0.01em<span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing--caps</span><span class="token punctuation">:</span> 0.05em<span class="token punctuation">;</span>

  <span class="token comment">/* Spacing */</span>
  <span class="token property">--spacing-heading-block</span><span class="token punctuation">:</span> 1.5rem 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Base heading styles */</span>
<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--heading-base-size<span class="token punctuation">)</span> *
      <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--typographic-scale<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-max-level<span class="token punctuation">)</span> - <span class="token function">sibling-index</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-heading<span class="token punctuation">,</span> <span class="token string">'Georgia'</span><span class="token punctuation">,</span> serif<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-font-weight<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-line-height<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">letter-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-letter-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">margin-block</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-heading-block<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">word-wrap</span><span class="token punctuation">:</span> break-word<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Tiered weights */</span>
<span class="token selector">:heading(1, 2, 3)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-font-weight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-font-weight--strong<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-letter-spacing--tight<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading(4, 5, 6)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-font-weight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-font-weight<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-letter-spacing--loose<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-heading-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Special case for h6 */</span>
<span class="token selector">:heading(6)</span> <span class="token punctuation">{</span>
  <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span>
  <span class="token property">--heading-letter-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-letter-spacing--caps<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Responsive adjustments */</span>
<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width >= 768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-major-third<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--heading-base-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width >= 1400px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--scale-perfect-fourth<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Dark mode */</span>
<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-heading</span><span class="token punctuation">:</span> #ecf0f1<span class="token punctuation">;</span>
    <span class="token property">--color-heading-secondary</span><span class="token punctuation">:</span> #bdc3c7<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>This follows Mike's <a href="https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/">cascading custom property strategy</a>, so css custom properties can be overridden contextually without duplicating rules.</p>
</div></div>
<p>This gives you a complete, flexible, maintainable heading system. It keeps mathematical precision for sizing, adapts to different contexts, responds to viewport size, supports theming, and can be updated globally with a single variable change.</p>
<h2 id="what-works-in-real-layouts" tabindex="-1">What Works in Real Layouts</h2>
<p>If you want the scale to work even when headings repeat or skip levels, you can assign the level explicitly and keep the maths intact. This removes the dependency on sibling order.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-base-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--typographic-scale</span><span class="token punctuation">:</span> 1.25<span class="token punctuation">;</span> <span class="token comment">/* Major Third */</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--heading-base-size<span class="token punctuation">)</span> *
      <span class="token function">pow</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--typographic-scale<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-level<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading(1)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 5<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(2)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 4<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(3)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 3<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(4)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(5)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">:heading(6)</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-level</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>It’s a few more lines, but it behaves correctly no matter how your headings are ordered in the markup.</p>
<div class="at-g-feature">
    <iframe height="600" style="width: 100%;" scrolling="no" title="Typographic Scales with :heading(), pow, and sibling-index()" src="https://codepen.io/sturobson/embed/KwMLKLg?default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
      See the Pen <a href="https://codepen.io/sturobson/pen/KwMLKLg">
  Typographic Scales with :heading(), pow, and sibling-index()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
      </iframe>
</div>
<h2 id="why-this-matters" tabindex="-1">Why This Matters</h2>
<p>This approach nudges how we think about CSS. Instead of declaring individual values, we're defining systems and letting CSS calculate the details.</p>
<p>Values update based on context, viewport, and user preferences. The mathematical relationship is expressed once and applied everywhere. Want to try a different scale? Change one variable. Want to adjust all heading sizes? Change the base size. The relationships remain consistent.</p>
<h2 id="browser-support-and-testing" tabindex="-1">Browser Support and Testing</h2>
<p>Safari Technology Preview is currently the only browser that supports all three features used here.</p>
<p>If you want to track progress or add support signals, here are the two issues to star or follow:</p>
<ul>
<li><a href="https://issues.chromium.org/issues/438147580"><code>:heading</code> (Chrome)</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1953973"><code>sibling-index()</code> (Firefox)</a></li>
<li><a href="https://bugs.webkit.org/show_bug.cgi?id=296994"><code>:heading</code> and <code>heading()</code> (Safari)</a></li>
</ul>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>The combination of <code>:heading()</code>, <code>sibling-index()</code>, and <code>pow()</code> can transform typographic scales from a tedious process into an elegant, mathematical system.</p>
<p>You define the rules once, and CSS handles the calculations.</p>
<p>This is more than a convenience feature.</p>
<p>It's a glimpse into a future where we can express design systems as mathematical relationships rather than exhaustive declarations. The code becomes more maintainable and more flexible.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Style Headings using the CSS :heading pseudo-class</title>
      <link href="https://www.alwaystwisted.com/articles/styling-with-the-heading-pseudo-class.html"/>
      <updated>2026-02-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/styling-with-the-heading-pseudo-class.html</id>
      <content type="html">
        <![CDATA[
        <p>The <code>:heading</code> pseudo-class lets us target all heading elements (<code>h1</code> through <code>h6</code>) with a single CSS rule, rather than writing out a verbose selector group every time we need to.</p>
<p>It's a small change, but it represents a shift toward better, more intentional and 'semantic' CSS.</p>
<h2 id="the-current-approach" tabindex="-1">The Current Approach</h2>
<p>Before <code>:heading</code>, whenever we wanted to apply the same styles to some or all headings, we had to list every heading element:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">h1,
h2,
h3,
h4,
h5,
h6</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Georgia'</span><span class="token punctuation">,</span> serif<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This works perfectly fine, but it's kinda verbose, especially if we're resetting some rules for specific headings. And if we're working with a large codebase or two, we might find ourselves repeating this pattern across multiple files.</p>
<p>It's not exactly a disaster, but it feels a bit untidy.</p>
<h2 id="enter-%3Aheading" tabindex="-1">Enter <code>:heading</code></h2>
<p>The <code>:heading</code> pseudo-class solves this with a cleaner, more semantic syntax:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Georgia'</span><span class="token punctuation">,</span> serif<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #333<span class="token punctuation">;</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This is much nicer, it clearly reads &quot;for all heading elements, apply these styles.&quot;. The intent should be immediately obvious. Here's what that looks like in action:</p>
<div class="at-g-feature">
<iframe height="600" style="width: 100%;" scrolling="no" title=":heading example" src="https://codepen.io/sturobson/embed/MYexYJq??default-tab=result" frameborder="no" loading="lazy" allowtransparency="true">
      See the Pen <a href="https://codepen.io/sturobson/pen/MYexYJq/826492d5570a5ac12bb402b8c4a55a37">
  :heading example</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
      </iframe>
</div>
<h2 id="targeting-specific-heading-levels" tabindex="-1">Targeting Specific Heading Levels</h2>
<p>While <code>:heading</code> lets us target all headings at once, we often want to apply different styles to different heading levels. The <code>:heading()</code> functional notation lets us do this by grouping heading levels together:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Major headings - larger and bolder */</span>
<span class="token selector">:heading(1, 2, 3)</span> <span class="token punctuation">{</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
  <span class="token property">letter-spacing</span><span class="token punctuation">:</span> -0.02em<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Secondary headings - smaller and lighter */</span>
<span class="token selector">:heading(4, 5, 6)</span> <span class="token punctuation">{</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">letter-spacing</span><span class="token punctuation">:</span> -0.01em<span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This approach of grouping headings into &quot;tiers&quot; within the design system lets us apply different styling rules without listing out each individual heading element (h1, h2, h3, etc.).</p>
<p>As a working principle, use <code>:heading</code> for properties that should be universal (font-family, line-height), and <code>:heading()</code> when different levels genuinely need different treatments (font-size, font-weight).</p>
<h3 id="specificity-considerations" tabindex="-1">Specificity Considerations</h3>
<p>One little thing to keep in mind: <code>:heading</code> has a specificity that's the same as a class selector (<code>0-1-0</code>).</p>
<p>Compare this to the old multi-selector approach:</p>
<ul>
<li><code>:heading</code> = <code>0-1-0</code></li>
<li><code>h1, h2, h3, h4, h5, h6</code> = <code>0-0-1</code></li>
</ul>
<p>This means that <code>:heading</code> should override styles on individual heading elements if both are present. This is usually what we want, but it's worth noting this for when we're debugging cascade issues.</p>
<h2 id="some-possible-use-cases" tabindex="-1">Some Possible Use Cases</h2>
<h3 id="consistent-typography" tabindex="-1">Consistent Typography</h3>
<p>The most straightforward use case is ensuring all headings follow the same typographic rules:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">letter-spacing</span><span class="token punctuation">:</span> -0.02em<span class="token punctuation">;</span>
  <span class="token property">word-wrap</span><span class="token punctuation">:</span> break-word<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This keeps our heading hierarchy consistent without having to repeat ourselves. Line height, letter spacing, and font weight are the kinds of properties that should be uniform across all heading levels, and <code>:heading</code> lets us set them once.</p>
<h3 id="component-specific-heading-styles" tabindex="-1">Component-Specific Heading Styles</h3>
<p>In component systems, the same heading level (say, an h3) might need different treatments depending on where it lives. With <code>:heading</code>, we set base styles once, then customise per-component:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Base heading styles that apply everywhere */</span>
<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* In a card, headings get a bottom border and different color */</span>
<span class="token selector">.card :heading</span> <span class="token punctuation">{</span>
  <span class="token property">border-bottom</span><span class="token punctuation">:</span> 2px solid <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-card-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding-bottom</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* In a sidebar, headings are smaller and uppercase */</span>
<span class="token selector">.sidebar :heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 0.875rem<span class="token punctuation">;</span>
  <span class="token property">text-transform</span><span class="token punctuation">:</span> uppercase<span class="token punctuation">;</span>
  <span class="token property">letter-spacing</span><span class="token punctuation">:</span> 0.05em<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* In modals, headings get extra spacing */</span>
<span class="token selector">.modal :heading</span> <span class="token punctuation">{</span>
  <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Without <code>:heading</code>, we'd define the base font, weight, and line-height separately for each component selector. With <code>:heading</code>, we define them once and let components add only the differences they need.</p>
<h3 id="font-family-and-weight-enforcement-across-components" tabindex="-1">Font Family and Weight Enforcement Across Components</h3>
<p>In a component system, a title in a Card, a heading in a Modal, and a subtitle in a Hero section could all share the same foundational typography—same font family, same font weight, same line height, but they just differ in font size.</p>
<p>With <code>:heading</code>, this is easy:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* All headings across the entire system */</span>
<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Inter'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Each component only customises what's unique to it */</span>
<span class="token selector">.card :heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.modal :heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.hero :heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 2.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Without <code>:heading</code>, we'd have to repeat the font-family, font-weight, and line-height in every component:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Without :heading - repetitive and fragile */</span>
<span class="token selector">.card h1,
.card h2,
.card h3,
.card h4,
.card h5,
.card h6</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Inter'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card h1</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.card h2</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* ... and repeat for modal, hero, etc. */</span>

<span class="token selector">.modal h1,
.modal h2,
.modal h3,
.modal h4,
.modal h5,
.modal h6</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Inter'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> 600<span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> 1.2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.modal h1</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* ... and again for hero ... */</span></code></pre>
<h2 id="composing-%3Aheading-with-other-selectors" tabindex="-1">Composing :heading With Other Selectors</h2>
<p>Beyond component-specific styles, <code>:heading</code> works well with other CSS patterns:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Variant modifiers - useful for design system components */</span>
<span class="token selector">:heading.error</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">:heading.success</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-success<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Sibling combinator - manage spacing between consecutive headings */</span>
<span class="token selector">:heading + :heading</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Headings inside interactive elements */</span>
<span class="token selector">button :heading,
a :heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> inherit<span class="token punctuation">;</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>These patterns avoid repeating the same rule for h1, h2, h3, etc. in each context. This composability is what makes <code>:heading</code> so valuable in larger systems.</p>
<h2 id="browser-support-and-testing" tabindex="-1">Browser Support and Testing</h2>
<p>The <code>:heading</code> pseudo-class is currently available in nightly builds only. You can test it now in:</p>
<ul>
<li>Firefox Nightly (behind a flag)</li>
<li>Safari Technology Preview</li>
</ul>
<p>If you want to see this in Chrome you can <a href="https://issues.chromium.org/issues/438147580">star this issue</a></p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The more developers who test <code>:heading</code> in nightly builds and advocate for the feature, the faster it's likely to be prioritised for stable release. Browser vendors pay attention to developer adoption and demand.</p>
</div></div>
<h2 id="a-cleaner-design-system" tabindex="-1">A Cleaner Design System</h2>
<p>If we're building a design system or component library, <code>:heading</code> can be particularly useful.</p>
<p>We can define base heading styles once and know they'll apply everywhere:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Base heading styles with defaults */</span>
<span class="token selector">:heading</span> <span class="token punctuation">{</span>
  <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">font-weight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-font-weight<span class="token punctuation">,</span> 600<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">line-height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-line-height<span class="token punctuation">,</span> 1.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-heading<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">margin-block</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-heading-block<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--heading-font-size<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Heading-specific variations using custom property overrides */</span>
<span class="token selector">h1</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-h1<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">h2</span> <span class="token punctuation">{</span>
  <span class="token property">--heading-font-size</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-h2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* And so on... */</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>This approach follows <a href="https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/">Mike Riethmuller's strategy</a> of using CSS custom properties to create overrideable defaults. Set custom properties that cascade naturally and get picked up by the base <code>:heading</code> rule, and we'll reduce repetition while making it easier to customise individual heading levels.</p>
</div></div>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>The <code>:heading</code> pseudo-class is a small but lovely addition to CSS that will make styling headings feel less repetitive.</p>
<p>Combined with CSS custom properties, it can become even more powerful, letting us manage heading styles consistently across entire design systems with minimal code.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 14) - Using Notion With Style Dictionary for Design Tokens Management</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-14.html"/>
      <updated>2026-02-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-14.html</id>
      <content type="html">
        <![CDATA[
        <p>Design tokens are great for developers, but what about everyone else on your team? The designers, product managers, and stakeholders who need to contribute without touching code?</p>
<p>JSON files work well for machines, but they're not exactly inviting for non-technical folks. That's where Notion comes in. It's the perfect bridge between your design system and the rest of your organisation.</p>
<p>In this tutorial, I'll show you how to set up a collaborative design token workflow using Notion as a user-friendly interface and Style Dictionary to generate platform-specific output. Changes made in Notion automatically sync to your codebase, and you can even push edits back for team review.</p>
<p>All the code and scripts mentioned in this tutorial are available in a <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/14-notion-design-tokens">GitHub repository for easy download and use</a></p>
<h2 id="benefits-of-this-approach" tabindex="-1">Benefits of This Approach</h2>
<p>Using Notion for design token management offers several advantages:</p>
<ul>
<li><strong>Accessibility</strong>: Non-technical team members can view, comment on, and propose token changes without touching code</li>
<li><strong>Collaboration</strong>: Built-in comments, version history, and real-time updates keep the team synchronised</li>
<li><strong>Organization</strong>: Database views allow filtering, sorting, and organizing tokens by category, status, or type</li>
<li><strong>Documentation</strong>: Rich content can be added alongside token values for context and usage guidelines</li>
<li><strong>Approval Workflow</strong>: Status fields manage which tokens are draft, in review, approved, or deprecated</li>
</ul>
<h2 id="setting-up-your-notion-database" tabindex="-1">Setting Up Your Notion Database</h2>
<p>Create a Notion database with the following properties:</p>
<ul>
<li><strong>Name</strong> (Title): The token name (e.g., &quot;Primary Blue&quot;)</li>
<li><strong>Token Path</strong> (Text): The path Style Dictionary will use (e.g., &quot;color.brand.primary&quot;)</li>
<li><strong>Value</strong> (Text): The actual value (e.g., &quot;#007bff&quot;)</li>
<li><strong>Type</strong> (Select): The token type (color, dimension, fontFamily, fontWeight, etc.)</li>
<li><strong>Category</strong> (Select): How the token is grouped (brand, semantic, component, foundation, etc.)</li>
<li><strong>Description</strong> (Text): Notes on what the token is for and when to use it</li>
<li><strong>Status</strong> (Select): Draft, Review, Approved, Deprecated</li>
</ul>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-database-categorgies.jpg" 
    alt="Screenshot of an empty Notion database showing column headers for design token properties"
    loading="lazy"
  >
  <figcaption>A Notion database configured with properties for Name, Token Path, Value, Type, Category, Description, and Status columns.</figcaption>
</figure>
<p>Once your database is set up with these properties, you can start adding your design tokens. The <strong>Status</strong> field controls which tokens get synced. By default, only &quot;Approved&quot; tokens are pulled into your build, creating a natural approval workflow before changes reach production.</p>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-database.jpg" 
    alt="Notion database with example tokens"
    loading="lazy"
  >
  <figcaption>A populated Notion database showing three example design tokens: Primary Blue (color), Base Spacing (dimension), and Heading Font (fontFamily). Each token has its corresponding properties filled in and Status set to Approved.</figcaption>
</figure>
<h3 id="token-path-format" tabindex="-1">Token Path Format</h3>
<p>The <strong>Token Path</strong> determines the structure of your generated CSS variables.</p>
<ul>
<li>Use dot notation: <code>color.brand.primary</code> becomes <code>--color-brand-primary</code></li>
<li>Each level creates a nested structure: <code>typography.size.base</code> becomes <code>--typography-size-base</code></li>
<li>Nested paths organise your token tree in the JSON output</li>
</ul>
<p>The Style Dictionary build will succeed even with incorrect paths, but won't generate what you expect.</p>
<h2 id="setting-up-the-notion-integration" tabindex="-1">Setting Up the Notion Integration</h2>
<p>Connecting Notion to your build process requires several steps. Complete them in order.</p>
<h3 id="step-1%3A-create-the-integration" tabindex="-1">Step 1: Create the Integration</h3>
<ol>
<li>Go to <a href="https://www.notion.com/my-integrations">https://www.notion.com/my-integrations</a></li>
<li>Click <strong>+ New integration</strong></li>
<li>Give it a name (e.g., &quot;Design Tokens Sync&quot;)</li>
<li>Select your workspace</li>
<li>Under <strong>Capabilities</strong>, make sure &quot;Read content&quot; is checked</li>
<li>Click <strong>Save</strong></li>
<li>Copy your <strong>Internal Integration Token</strong> (the long string starting with <code>ntn_</code>)</li>
<li>Store this securely, it's your API key for accessing Notion</li>
</ol>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-my-integration-page.jpg" 
    alt="Notion My Integrations page"
    loading="lazy"
  >
  <figcaption>The Notion My integrations page showing the integration creation form with fields for Name (Design Tokens Sync), Workspace selection, and Capabilities toggle with Read content enabled.</figcaption>
</figure>
<p>After creating the integration, you'll see the integration details page where you can copy your <strong>Internal Integration Token</strong>.</p>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-integration-settings.jpg" 
    alt="Notion integration token"
    loading="lazy"
  >
  <figcaption>The successfully created integration showing the Internal Integration Token field with the token value (redacted in production) ready to be copied. Note the security warning to keep this token secure.</figcaption>
</figure>
<h3 id="step-2%3A-get-your-database-id" tabindex="-1">Step 2: Get Your Database ID</h3>
<p>You need the actual <em>database</em> ID, not the parent page ID.</p>
<ol>
<li>Open your Notion database (the table view)</li>
<li>Copy the URL from your browser</li>
<li>It looks like: <code>https://www.notion.so/abc123def456ghi789jkl?v=xyz&amp;t=123</code></li>
<li>The database ID is the part <strong>before the <code>?v=</code></strong> (the long hex string)</li>
<li>Save this ID</li>
</ol>
<h3 id="step-3%3A-connect-the-integration-to-your-database" tabindex="-1">Step 3: Connect the Integration to Your Database</h3>
<p>This step is critical, skipping it causes &quot;database not found&quot; errors.</p>
<ol>
<li>Open your Notion database</li>
<li>Click the <strong>•••</strong> menu in the top right corner</li>
<li>Scroll to <strong>Connections</strong></li>
<li>Click <strong>+ Add connections</strong> (or <strong>Confirm access</strong> if shown)</li>
<li>Select your integration name</li>
<li>Confirm access</li>
</ol>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-database-menu.jpg" 
    alt="Notion database menu"
    loading="lazy"
  >
  <figcaption>The Notion database page with the three-dot menu in the top right corner expanded, showing various options including the Connections section.</figcaption>
</figure>
<p>From the menu, select <strong>+ Add connections</strong> to grant your integration access to this specific database.</p>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/notion-add-connections.jpg" 
    alt="Notion add connections dialog"
    loading="lazy"
  >
  <figcaption>The Add connections dialog showing the list of available integrations. The Design Tokens Sync integration is highlighted and ready to be selected to grant database access.</figcaption>
</figure>
<p>The integration now has permission to read from that database. Without this, the API will reject all requests with a 404 error.</p>
<h3 id="step-4%3A-set-up-your-development-environment" tabindex="-1">Step 4: Set Up Your Development Environment</h3>
<p>Now that your Notion integration is configured, let's set up your local development environment.</p>
<p>First, install the required npm packages:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> @notionhq/client style-dictionary dotenv nodemon</code></pre>
<p>Create a <code>.env</code> file in your project root with your Notion credentials:</p>
<pre class="language-env"><code class="language-env">NOTION_TOKEN=ntn_your_long_token_here
NOTION_DATABASE_ID=abc123def456ghi789jkl</code></pre>
<p>Make sure your <code>package.json</code> has <code>&quot;type&quot;: &quot;module&quot;</code> so you can use ES modules:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"module"</span><span class="token punctuation">,</span>
  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"design-tokens"</span><span class="token punctuation">,</span>
  <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span>
  ...
<span class="token punctuation">}</span></code></pre>
<p>That's it! You're ready to sync.</p>
<h2 id="fetching-tokens-from-notion" tabindex="-1">Fetching Tokens from Notion</h2>
<p>Create a file called <code>fetch-tokens.js</code> that pulls approved tokens from Notion and generates a JSON file for Style Dictionary.</p>
<p>First, let's set up the imports and initialise the Notion client:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Client <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@notionhq/client'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">'fs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> path <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> fileURLToPath <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'url'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> dotenv <span class="token keyword">from</span> <span class="token string">'dotenv'</span><span class="token punctuation">;</span>

dotenv<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> __filename <span class="token operator">=</span> <span class="token function">fileURLToPath</span><span class="token punctuation">(</span><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> __dirname <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">dirname</span><span class="token punctuation">(</span>__filename<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Initialise Notion client</span>
<span class="token keyword">const</span> notion <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Client</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">auth</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NOTION_TOKEN</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> databaseId <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NOTION_DATABASE_ID</span><span class="token punctuation">;</span></code></pre>
<p>Next, create a function to fetch all approved tokens from your Notion database. This handles pagination since Notion returns results in batches:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Fetch all approved tokens from Notion database
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchTokensFromNotion</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> allResults <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> hasMore <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> startCursor <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

    <span class="token comment">// Handle pagination</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span>hasMore<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> notion<span class="token punctuation">.</span>databases<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">database_id</span><span class="token operator">:</span> databaseId<span class="token punctuation">,</span>
        <span class="token literal-property property">start_cursor</span><span class="token operator">:</span> startCursor<span class="token punctuation">,</span>
        <span class="token literal-property property">filter</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'Status'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">equals</span><span class="token operator">:</span> <span class="token string">'Approved'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      allResults <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>allResults<span class="token punctuation">,</span> <span class="token operator">...</span>response<span class="token punctuation">.</span>results<span class="token punctuation">]</span><span class="token punctuation">;</span>
      hasMore <span class="token operator">=</span> response<span class="token punctuation">.</span>has_more<span class="token punctuation">;</span>
      startCursor <span class="token operator">=</span> response<span class="token punctuation">.</span>next_cursor<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> allResults<span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error fetching from Notion:'</span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">throw</span> error<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Now we need a function to extract the token data from Notion's page properties format into a simpler structure:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Extract token data from Notion page properties
 */</span>
<span class="token keyword">function</span> <span class="token function">extractTokenData</span><span class="token punctuation">(</span><span class="token parameter">page</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> properties <span class="token operator">=</span> page<span class="token punctuation">.</span>properties<span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">id</span><span class="token operator">:</span> page<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Name<span class="token operator">?.</span>title<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> properties<span class="token punctuation">[</span><span class="token string">'Token Path'</span><span class="token punctuation">]</span><span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Value<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Type<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">category</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Category<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Status<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">'Draft'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">description</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Description<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The tokens need to be converted from a flat list into a nested JSON structure that Style Dictionary can understand. This function builds that tree:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Convert flat token list to nested JSON structure
 */</span>
<span class="token keyword">function</span> <span class="token function">buildTokenTree</span><span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> tree <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

  tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> pathParts <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> current <span class="token operator">=</span> tree<span class="token punctuation">;</span>

    pathParts<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">part<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">===</span> pathParts<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Last part - add the token</span>
        current<span class="token punctuation">[</span>part<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">$value</span><span class="token operator">:</span> token<span class="token punctuation">.</span>value<span class="token punctuation">,</span>
          <span class="token literal-property property">$type</span><span class="token operator">:</span> token<span class="token punctuation">.</span>type<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>description<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">.</span>$description <span class="token operator">=</span> token<span class="token punctuation">.</span>description<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">// Add Notion metadata as extensions</span>
        current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">.</span>$extensions <span class="token operator">=</span> <span class="token punctuation">{</span>
          <span class="token string-property property">'com.notion'</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">status</span><span class="token operator">:</span> token<span class="token punctuation">.</span>status<span class="token punctuation">,</span>
            <span class="token literal-property property">category</span><span class="token operator">:</span> token<span class="token punctuation">.</span>category<span class="token punctuation">,</span>
            <span class="token literal-property property">notionId</span><span class="token operator">:</span> token<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
            <span class="token literal-property property">lastSynced</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token comment">// Create nested object if it doesn't exist</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          current<span class="token punctuation">[</span>part<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        current <span class="token operator">=</span> current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> tree<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>To detect conflicts between local changes and Notion updates, we need to flatten the nested token structure back into an array for comparison:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Flatten nested token object back into array (for comparison/conflict detection)
 */</span>
<span class="token keyword">function</span> <span class="token function">flattenTokens</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> prefix <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> tokens <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> fullPath <span class="token operator">=</span> prefix <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> key<span class="token punctuation">;</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>value<span class="token punctuation">.</span>$value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// This is a token</span>
      tokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">path</span><span class="token operator">:</span> fullPath<span class="token punctuation">,</span>
        <span class="token literal-property property">value</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$value<span class="token punctuation">,</span>
        <span class="token literal-property property">type</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$type <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">description</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$description <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">category</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>category <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">status</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>status <span class="token operator">||</span> <span class="token string">'Draft'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">notionId</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>notionId <span class="token operator">||</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> value <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">&amp;&amp;</span> value <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Recurse for nested objects</span>
      tokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token function">flattenTokens</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> fullPath<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> tokens<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Finally, the main sync function that orchestrates everything:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Main function to sync tokens from Notion
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">syncTokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'🔄 Fetching tokens from Notion...'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> pages <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchTokensFromNotion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">✅ Found </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>pages<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> approved tokens\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> notionTokens <span class="token operator">=</span> pages<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>extractTokenData<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> newTokenTree <span class="token operator">=</span> <span class="token function">buildTokenTree</span><span class="token punctuation">(</span>notionTokens<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Create tokens directory if it doesn't exist</span>
  <span class="token keyword">const</span> tokensDir <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">recursive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Check for conflicts with existing tokens.json</span>
  <span class="token keyword">const</span> outputPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">,</span> <span class="token string">'tokens.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> existingTokens <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> conflicts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>outputPath<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> existingData <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>outputPath<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      existingTokens <span class="token operator">=</span> <span class="token function">flattenTokens</span><span class="token punctuation">(</span>existingData<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span>
        <span class="token string">'⚠️  Could not read existing tokens.json, treating as new file\n'</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Flatten new tokens for comparison</span>
  <span class="token keyword">const</span> flatNewTokens <span class="token operator">=</span> <span class="token function">flattenTokens</span><span class="token punctuation">(</span>newTokenTree<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Check for conflicts (token exists in both but with different values)</span>
  flatNewTokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">newToken</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> existing <span class="token operator">=</span> existingTokens<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">t</span><span class="token punctuation">)</span> <span class="token operator">=></span> t<span class="token punctuation">.</span>path <span class="token operator">===</span> newToken<span class="token punctuation">.</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>existing <span class="token operator">&amp;&amp;</span> existing<span class="token punctuation">.</span>value <span class="token operator">!==</span> newToken<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      conflicts<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">path</span><span class="token operator">:</span> newToken<span class="token punctuation">.</span>path<span class="token punctuation">,</span>
        <span class="token literal-property property">local</span><span class="token operator">:</span> existing<span class="token punctuation">.</span>value<span class="token punctuation">,</span>
        <span class="token literal-property property">notion</span><span class="token operator">:</span> newToken<span class="token punctuation">.</span>value<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Report what we found</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>conflicts<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">⚠️  Found </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conflicts<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> conflicts (local changes != Notion):</span><span class="token template-punctuation string">`</span></span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
    conflicts<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">conflict</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conflict<span class="token punctuation">.</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">     Local: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conflict<span class="token punctuation">.</span>local<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">     Notion: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>conflict<span class="token punctuation">.</span>notion<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">\nSyncing from Notion (Notion values take precedence)\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Write tokens to JSON file (Notion is source of truth)</span>
  fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>outputPath<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>newTokenTree<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">💾 Tokens saved to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>outputPath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'✨ Sync complete!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> newTokenTree<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Run if called directly</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url <span class="token operator">===</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">file://</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>process<span class="token punctuation">.</span>argv<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token function">syncTokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> syncTokens <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>What the sync script does:</p>
<ol>
<li><strong>Fetches approved tokens</strong> from your Notion database</li>
<li><strong>Compares with existing tokens.json</strong> to detect conflicts</li>
<li><strong>Reports any differences</strong>: If you've edited a token locally and it changed in Notion, you'll see a warning</li>
<li><strong>Syncs from Notion</strong>: Notion is always the source of truth, so the Notion values win</li>
<li><strong>Preserves metadata</strong>: Keeps the <code>$extensions</code> and Notion IDs for future syncs and pushes</li>
</ol>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/sync-script-terminal-output.jpg" 
    alt="Sync script terminal output"
    loading="lazy"
  >
  <figcaption>Terminal output showing the successful execution of the sync script. The display includes emoji indicators for different stages, conflict detection and resolution messaging, and final confirmation with indicators.</figcaption>
</figure>
<p>This way you know exactly what changed and won't be surprised by overwritten values.</p>
<h2 id="integrating-with-style-dictionary" tabindex="-1">Integrating With Style Dictionary</h2>
<p>Once tokens are syncing from Notion, create a <code>build.js</code> file that runs Style Dictionary to generate platform-specific files.</p>
<p>First, set up the imports and environment:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">'fs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> path <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> fileURLToPath <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'url'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> dotenv <span class="token keyword">from</span> <span class="token string">'dotenv'</span><span class="token punctuation">;</span>

dotenv<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> __filename <span class="token operator">=</span> <span class="token function">fileURLToPath</span><span class="token punctuation">(</span><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> __dirname <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">dirname</span><span class="token punctuation">(</span>__filename<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> notionDatabaseId <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NOTION_DATABASE_ID</span><span class="token punctuation">;</span></code></pre>
<p>This function adds a header comment to generated files with Notion metadata:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Add Notion metadata comment to generated files
 */</span>
<span class="token keyword">function</span> <span class="token function">addNotionHeader</span><span class="token punctuation">(</span><span class="token parameter">filePath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> notionUrl <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://www.notion.so/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>notionDatabaseId<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> header <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
 * Do not edit directly, this file was auto-generated.
 * 
 * Generated from Notion Design Tokens
 * Database: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>notionUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
 * Last updated: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toISOString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> content <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>filePath<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> lines <span class="token operator">=</span> content<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Remove all comment blocks at the top of the file</span>
  <span class="token keyword">let</span> contentStartIndex <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> inComment <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>

  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> lines<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>lines<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'/**'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      inComment <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>inComment <span class="token operator">&amp;&amp;</span> lines<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'*/'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      contentStartIndex <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
      <span class="token comment">// Skip empty lines after comment</span>
      <span class="token keyword">while</span> <span class="token punctuation">(</span>
        contentStartIndex <span class="token operator">&lt;</span> lines<span class="token punctuation">.</span>length <span class="token operator">&amp;&amp;</span>
        lines<span class="token punctuation">[</span>contentStartIndex<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">''</span>
      <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        contentStartIndex<span class="token operator">++</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> newContent <span class="token operator">=</span>
    header <span class="token operator">+</span> lines<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span>contentStartIndex<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">trimStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>filePath<span class="token punctuation">,</span> newContent<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The main build function runs Style Dictionary to generate platform files:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'🏗️  Building with Style Dictionary...\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Configure Style Dictionary</span>
  <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/scss/'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'_variables.scss'</span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token literal-property property">js</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/js/'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens.js'</span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/es6'</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Build all platforms</span>
  <span class="token keyword">await</span> sd<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Add Notion metadata to generated files</span>
  <span class="token function">addNotionHeader</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'build/css/variables.css'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token function">addNotionHeader</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'build/scss/_variables.scss'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'\n✅ Build complete!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span>console<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/build-script-terminal-output.jpg" 
    alt="Terminal window showing successful Style Dictionary build output with checkmarks for CSS, SCSS, and JS files"
    loading="lazy"
  >
  <figcaption>Build script terminal output showing the successful completion of the Style Dictionary build process.</figcaption>
</figure>
<h2 id="adding-advanced-features" tabindex="-1">Adding Advanced Features</h2>
<p>Once the basic workflow is in place, consider these optional enhancements:</p>
<h3 id="organizing-by-category" tabindex="-1">Organizing by Category</h3>
<p>If you want to keep tokens organised by category (which can be useful with large token sets):</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">syncTokensByCategory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pages <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchTokensFromNotion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> tokens <span class="token operator">=</span> pages<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>extractTokenData<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Group by category</span>
  <span class="token keyword">const</span> categories <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
  tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> category <span class="token operator">=</span> token<span class="token punctuation">.</span>category <span class="token operator">||</span> <span class="token string">'general'</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>categories<span class="token punctuation">[</span>category<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      categories<span class="token punctuation">[</span>category<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    categories<span class="token punctuation">[</span>category<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Write separate files per category</span>
  <span class="token keyword">const</span> tokensDir <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">recursive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>categories<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">category</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> tree <span class="token operator">=</span> <span class="token function">buildTokenTree</span><span class="token punctuation">(</span>categories<span class="token punctuation">[</span>category<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> outputPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>tokensDir<span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>category<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>outputPath<span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>tree<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">💾 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>category<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens saved to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>outputPath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="validating-token-data" tabindex="-1">Validating Token Data</h3>
<p>Add basic validation to catch issues early, invalid color values, malformed dimensions, and other data problems:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">validateToken</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> errors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>token<span class="token punctuation">.</span>path<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    errors<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'Missing token path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>token<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    errors<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'Missing token value'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>token<span class="token punctuation">.</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    errors<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token string">'Missing token type'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Validate color format</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> hexPattern <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>hexPattern<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      errors<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Invalid color format: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Validate dimension format</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>type <span class="token operator">===</span> <span class="token string">'dimension'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> dimensionPattern <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\d+(\.\d+)?(px|rem|em|%)$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dimensionPattern<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      errors<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Invalid dimension format: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> errors<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Use in extractTokenData</span>
<span class="token keyword">function</span> <span class="token function">extractTokenData</span><span class="token punctuation">(</span><span class="token parameter">page</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> properties <span class="token operator">=</span> page<span class="token punctuation">.</span>properties<span class="token punctuation">;</span>

  <span class="token keyword">const</span> token <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">id</span><span class="token operator">:</span> page<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Name<span class="token operator">?.</span>title<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> properties<span class="token punctuation">[</span><span class="token string">'Token Path'</span><span class="token punctuation">]</span><span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Value<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Type<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">category</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Category<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
    <span class="token literal-property property">status</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Status<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">'Draft'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">description</span><span class="token operator">:</span> properties<span class="token punctuation">.</span>Description<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> errors <span class="token operator">=</span> <span class="token function">validateToken</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>errors<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">⚠️  Validation errors for "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">":</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> errors<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">return</span> token<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="using-token-references" tabindex="-1">Using Token References</h3>
<p>One feature I find useful is the ability to reference other tokens. So if you want one token to use the value of another:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">buildTokenTree</span><span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> tree <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

  tokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> pathParts <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> current <span class="token operator">=</span> tree<span class="token punctuation">;</span>

    pathParts<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">part<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">===</span> pathParts<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Check if value is a reference (starts with {)</span>
        <span class="token keyword">const</span> isReference <span class="token operator">=</span>
          token<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'{'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>value<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'}'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        current<span class="token punctuation">[</span>part<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">value</span><span class="token operator">:</span> isReference <span class="token operator">?</span> token<span class="token punctuation">.</span>value <span class="token operator">:</span> token<span class="token punctuation">.</span>value<span class="token punctuation">,</span>
          <span class="token literal-property property">$type</span><span class="token operator">:</span> token<span class="token punctuation">.</span>type<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>description<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">.</span>$description <span class="token operator">=</span> token<span class="token punctuation">.</span>description<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          current<span class="token punctuation">[</span>part<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        current <span class="token operator">=</span> current<span class="token punctuation">[</span>part<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> tree<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>In your Notion database, you can now use references like:</p>
<ul>
<li>Value: <code>{color.brand.primary}</code></li>
</ul>
<p>Style Dictionary will automatically resolve these references during the build process.</p>
<h3 id="preserving-notion-metadata-with-%24extensions" tabindex="-1">Preserving Notion Metadata With $extensions</h3>
<p>Keep Notion metadata in your generated JSON files using the Design Tokens <code>$extensions</code> field, which is designed specifically for custom metadata.</p>
<p>The sync script includes this by default, each token gets an <code>$extensions</code> object that tracks:</p>
<ul>
<li><strong>status</strong>: Whether the token is Draft, Review, Approved, or Deprecated</li>
<li><strong>category</strong>: How the token is grouped</li>
<li><strong>notionId</strong>: The unique ID of the Notion page (useful for linking back)</li>
<li><strong>lastSynced</strong>: When the token was last pulled from Notion</li>
</ul>
<p>This means your generated JSON looks like this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary brand color"</span><span class="token punctuation">,</span>
      <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"com.notion"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"status"</span><span class="token operator">:</span> <span class="token string">"Approved"</span><span class="token punctuation">,</span>
          <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"brand"</span><span class="token punctuation">,</span>
          <span class="token property">"notionId"</span><span class="token operator">:</span> <span class="token string">"a1b2c3d4e5f6g7h8"</span><span class="token punctuation">,</span>
          <span class="token property">"lastSynced"</span><span class="token operator">:</span> <span class="token string">"2026-02-09T10:30:00.000Z"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This metadata is useful for:</p>
<ul>
<li><strong>Audit trails</strong>: Track exactly when tokens changed and what their approval status was</li>
<li><strong>Debugging</strong>: Identify which Notion page a token came from without confusion</li>
<li><strong>Automation</strong>: Use the extension data in custom Style Dictionary transforms or other tools</li>
<li><strong>Documentation</strong>: Generated files become self-documenting with full context</li>
</ul>
<p>The <code>$extensions</code> field is optional, Style Dictionary and other tools treat it as optional metadata and work fine without it. For complex workflows or full audit trail tracking in version control, it's worth preserving.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>If you want to dive deeper into the <code>$extensions</code> specification and see real-world examples, check out my post <a href="https://www.alwaystwisted.com/articles/understanding-extensions-in-the-design-tokens-spec">Understanding $extensions in the Design Tokens Specification</a> and the <a href="https://www.alwaystwisted.com/projects/dtm/extensions/">Design Tokens Extensions Explorer</a> tool.</p>
</div></div>
<h2 id="updating-your-package.json" tabindex="-1">Updating Your package.json</h2>
<p>Add helpful scripts to your <code>package.json</code> for managing the workflow:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"design-tokens"</span><span class="token punctuation">,</span>
  <span class="token property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span>
  <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"module"</span><span class="token punctuation">,</span>
  <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"sync"</span><span class="token operator">:</span> <span class="token string">"node fetch-tokens.js"</span><span class="token punctuation">,</span>
    <span class="token property">"push"</span><span class="token operator">:</span> <span class="token string">"node push-tokens.js"</span><span class="token punctuation">,</span>
    <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"node build.js"</span><span class="token punctuation">,</span>
    <span class="token property">"sync:build"</span><span class="token operator">:</span> <span class="token string">"npm run sync &amp;&amp; npm run build"</span><span class="token punctuation">,</span>
    <span class="token property">"watch"</span><span class="token operator">:</span> <span class="token string">"nodemon --watch tokens -e json --exec npm run build"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"devDependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"@notionhq/client"</span><span class="token operator">:</span> <span class="token string">"^2.2.15"</span><span class="token punctuation">,</span>
    <span class="token property">"style-dictionary"</span><span class="token operator">:</span> <span class="token string">"^4.1.4"</span><span class="token punctuation">,</span>
    <span class="token property">"dotenv"</span><span class="token operator">:</span> <span class="token string">"^16.3.1"</span><span class="token punctuation">,</span>
    <span class="token property">"nodemon"</span><span class="token operator">:</span> <span class="token string">"^3.0.0"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This enables the following commands:</p>
<ul>
<li><code>npm run sync</code> - Fetch tokens from Notion</li>
<li><code>npm run push</code> - Push changes from JSON back to Notion</li>
<li><code>npm run build</code> - Build with Style Dictionary (without syncing)</li>
<li><code>npm run sync:build</code> - Sync tokens AND build (combined operation)</li>
<li><code>npm run watch</code> - Watch for token changes and rebuild</li>
</ul>
<h2 id="two-way-sync%3A-going-the-other-direction" tabindex="-1">Two-Way Sync: Going the Other Direction</h2>
<p>This workflow supports bidirectional syncing, pull tokens from Notion into your JSON, or push changes from your JSON back to Notion for team review.</p>
<p>Create a <code>push-tokens.js</code> script to enable pushing.</p>
<p>First, set up the imports and initialise the Notion client:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> Client <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@notionhq/client'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">'fs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> path <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> fileURLToPath <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'url'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> dotenv <span class="token keyword">from</span> <span class="token string">'dotenv'</span><span class="token punctuation">;</span>

dotenv<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> __filename <span class="token operator">=</span> <span class="token function">fileURLToPath</span><span class="token punctuation">(</span><span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> __dirname <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">dirname</span><span class="token punctuation">(</span>__filename<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> notion <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Client</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">auth</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NOTION_TOKEN</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> databaseId <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NOTION_DATABASE_ID</span><span class="token punctuation">;</span></code></pre>
<p>This function flattens the nested token structure back into an array for processing. It's the inverse of the buildTokenTree function:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Flatten nested token object into array for processing
 * This converts the hierarchical JSON structure back to a flat array
 */</span>
<span class="token keyword">function</span> <span class="token function">flattenTokens</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> prefix <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> tokens <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> fullPath <span class="token operator">=</span> prefix <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>key<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> key<span class="token punctuation">;</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> obj<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>value<span class="token punctuation">.</span>$value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// This is a token leaf node</span>
      tokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">path</span><span class="token operator">:</span> fullPath<span class="token punctuation">,</span>
        <span class="token literal-property property">value</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$value<span class="token punctuation">,</span>
        <span class="token literal-property property">type</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$type <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">description</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$description <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">category</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>category <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token literal-property property">status</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>status <span class="token operator">||</span> <span class="token string">'Draft'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">notionId</span><span class="token operator">:</span> value<span class="token punctuation">.</span>$extensions<span class="token operator">?.</span><span class="token punctuation">[</span><span class="token string">'com.notion'</span><span class="token punctuation">]</span><span class="token operator">?.</span>notionId <span class="token operator">||</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> value <span class="token operator">===</span> <span class="token string">'object'</span> <span class="token operator">&amp;&amp;</span> value <span class="token operator">!==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Recurse for nested objects (branches)</span>
      tokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token function">flattenTokens</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> fullPath<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> tokens<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This function updates an existing Notion page with new token values:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Update an existing Notion page with new token data
 * Only updates the fields that can be modified (value, type, category, description)
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">updateNotionPage</span><span class="token punctuation">(</span><span class="token parameter">pageId<span class="token punctuation">,</span> token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> notion<span class="token punctuation">.</span>pages<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token literal-property property">page_id</span><span class="token operator">:</span> pageId<span class="token punctuation">,</span>
      <span class="token literal-property property">properties</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">Value</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">rich_text</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Type</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> token<span class="token punctuation">.</span>type <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Category</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> token<span class="token punctuation">.</span>category <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Description</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">rich_text</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>description <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  ❌ Failed to update "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">":</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This function creates a new Notion page for tokens that don't exist yet:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Create a new Notion page in the database for a new token
 * New tokens are created with "Draft" status for review
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">createNotionPage</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">await</span> notion<span class="token punctuation">.</span>pages<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token literal-property property">parent</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">database_id</span><span class="token operator">:</span> databaseId <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token literal-property property">properties</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">Name</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>path <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token string-property property">'Token Path'</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">rich_text</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>path <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Value</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">rich_text</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Type</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> token<span class="token punctuation">.</span>type <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Category</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> token<span class="token punctuation">.</span>category <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Description</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">rich_text</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
              <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">content</span><span class="token operator">:</span> token<span class="token punctuation">.</span>description <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token literal-property property">Status</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">select</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Draft'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">// New tokens start as drafts</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  ❌ Failed to create "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">":</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This function fetches all existing tokens from Notion to compare against local changes:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Fetch all tokens currently in Notion database
 * Returns a map of token path -> Notion data for quick lookup
 * This is used to determine what exists in Notion vs. what we want to push
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchExistingTokensFromNotion</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> allPages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> hasMore <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> startCursor <span class="token operator">=</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>

    <span class="token comment">// Fetch all pages from database (not only approved ones)</span>
    <span class="token keyword">while</span> <span class="token punctuation">(</span>hasMore<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> notion<span class="token punctuation">.</span>databases<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">database_id</span><span class="token operator">:</span> databaseId<span class="token punctuation">,</span>
        <span class="token literal-property property">start_cursor</span><span class="token operator">:</span> startCursor<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

      allPages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>allPages<span class="token punctuation">,</span> <span class="token operator">...</span>response<span class="token punctuation">.</span>results<span class="token punctuation">]</span><span class="token punctuation">;</span>
      hasMore <span class="token operator">=</span> response<span class="token punctuation">.</span>has_more<span class="token punctuation">;</span>
      startCursor <span class="token operator">=</span> response<span class="token punctuation">.</span>next_cursor<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// Build lookup map of token path -> Notion data for fast comparison</span>
    <span class="token keyword">const</span> notionTokens <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

    allPages<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">page</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> props <span class="token operator">=</span> page<span class="token punctuation">.</span>properties<span class="token punctuation">;</span>
      <span class="token keyword">const</span> tokenPath <span class="token operator">=</span> props<span class="token punctuation">[</span><span class="token string">'Token Path'</span><span class="token punctuation">]</span><span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text<span class="token punctuation">;</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>tokenPath<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        notionTokens<span class="token punctuation">[</span>tokenPath<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">id</span><span class="token operator">:</span> page<span class="token punctuation">.</span>id<span class="token punctuation">,</span>
          <span class="token literal-property property">value</span><span class="token operator">:</span> props<span class="token punctuation">.</span>Value<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
          <span class="token literal-property property">type</span><span class="token operator">:</span> props<span class="token punctuation">.</span>Type<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
          <span class="token literal-property property">description</span><span class="token operator">:</span> props<span class="token punctuation">.</span>Description<span class="token operator">?.</span>rich_text<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token operator">?.</span>plain_text <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
          <span class="token literal-property property">category</span><span class="token operator">:</span> props<span class="token punctuation">.</span>Category<span class="token operator">?.</span>select<span class="token operator">?.</span>name <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> notionTokens<span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error fetching from Notion:'</span><span class="token punctuation">,</span> error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">throw</span> error<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This function compares local tokens with Notion versions to detect changes:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Compare local token with Notion version to detect changes
 * Returns true if the token needs to be updated in Notion
 */</span>
<span class="token keyword">function</span> <span class="token function">hasTokenChanged</span><span class="token punctuation">(</span><span class="token parameter">local<span class="token punctuation">,</span> notion</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>notion<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">// New token (doesn't exist in Notion yet)</span>

  <span class="token comment">// Check if any of the key properties differ</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    local<span class="token punctuation">.</span>value <span class="token operator">!==</span> notion<span class="token punctuation">.</span>value <span class="token operator">||</span>
    local<span class="token punctuation">.</span>type <span class="token operator">!==</span> notion<span class="token punctuation">.</span>type <span class="token operator">||</span>
    local<span class="token punctuation">.</span>description <span class="token operator">!==</span> notion<span class="token punctuation">.</span>description <span class="token operator">||</span>
    local<span class="token punctuation">.</span>category <span class="token operator">!==</span> notion<span class="token punctuation">.</span>category
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Finally, the main push function that orchestrates the entire process:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/**
 * Main function to push tokens to Notion
 * This implements a "smart sync" that only updates what has changed
 */</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">pushTokens</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'📤 Pushing tokens to Notion...\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Read current tokens from JSON</span>
  <span class="token keyword">const</span> tokensPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'tokens'</span><span class="token punctuation">,</span> <span class="token string">'tokens.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>tokensPath<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'❌ tokens/tokens.json not found. Run "npm run sync" first.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    process<span class="token punctuation">.</span><span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">const</span> tokensData <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>tokensPath<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> localTokens <span class="token operator">=</span> <span class="token function">flattenTokens</span><span class="token punctuation">(</span>tokensData<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Fetch current state from Notion for comparison</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'🔍 Checking Notion database for existing tokens...\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> notionTokens <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchExistingTokensFromNotion</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Categorise tokens: new, changed, or unchanged</span>
  <span class="token keyword">const</span> changedTokens <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> newTokens <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> unchangedTokens <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  localTokens<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> notionToken <span class="token operator">=</span> notionTokens<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>notionToken<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Token doesn't exist in Notion yet</span>
      newTokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">hasTokenChanged</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> notionToken<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token comment">// Token exists but has different values - needs update</span>
      token<span class="token punctuation">.</span>notionId <span class="token operator">=</span> notionToken<span class="token punctuation">.</span>id<span class="token punctuation">;</span> <span class="token comment">// Store ID for updating</span>
      changedTokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token comment">// Token exists and is identical</span>
      unchangedTokens<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Report what we found</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Found </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>localTokens<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens total:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  • </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>unchangedTokens<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> unchanged (skipping)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  • </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>changedTokens<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> changed</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  • </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>newTokens<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> new\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Exit early if nothing to do</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>changedTokens<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> newTokens<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Everything is already synced! Nothing to do.\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Push changes to Notion</span>
  <span class="token keyword">let</span> updated <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> created <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

  <span class="token comment">// Update existing tokens</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> token <span class="token keyword">of</span> changedTokens<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Updating "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"... </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">updateNotionPage</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>notionId<span class="token punctuation">,</span> token<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'✅'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      updated<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Create new tokens</span>
  <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> token <span class="token keyword">of</span> newTokens<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    process<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Creating "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">"... </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">await</span> <span class="token function">createNotionPage</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'✅'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      created<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">\n✅ Push complete!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   Updated: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>updated<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">   Created: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>created<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> new tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> pushTokens <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<figure class="at-c-figure--article-image at-g-popout">
  <img 
    src="/images/articles/notion/push-script-terminal-output.jpg" 
    alt="Push script terminal output"
    loading="lazy"
  >
  <figcaption>Terminal output showing the successful execution of the push script, including token updates and creations with progress indicators.</figcaption>
</figure>
<p>How this works:</p>
<ol>
<li><strong>Fetches from Notion</strong>: Queries the entire database to get current token state</li>
<li><strong>Builds a lookup map</strong>: Creates a fast dictionary of token path → current values</li>
<li><strong>Compares local vs. Notion</strong>: For each local token, checks if value, type, category, or description differs</li>
<li><strong>Only updates what changed</strong>: Only makes API calls for tokens that actually differ</li>
<li><strong>No hidden files</strong>: Everything is tracked by comparing against the live Notion database</li>
</ol>
<p><strong>This approach is better because:</strong></p>
<ul>
<li>No hidden <code>.lastPushed.json</code> files to manage</li>
<li>Single source of truth is always Notion</li>
<li>Works even if you skip a push or run the script multiple times</li>
<li>Transparent, you can see exactly what's different</li>
<li>Safe, only touches tokens that actually changed</li>
</ul>
<p>How it works:</p>
<ol>
<li><strong>Reads your JSON</strong>: Parses <code>tokens/tokens.json</code> and flattens the nested structure</li>
<li><strong>Matches tokens</strong>: Uses the <code>notionId</code> stored in <code>$extensions</code> to find which Notion page to update</li>
<li><strong>Updates or creates</strong>: For existing tokens, updates their values; for new ones, creates new Notion pages (marked as &quot;Draft&quot;)</li>
<li><strong>Preserves metadata</strong>: Keeps category, status, and description synced</li>
</ol>
<p>This is especially useful when:</p>
<ul>
<li>A developer tweaks a token value and wants that change reflected in Notion</li>
<li>You're bulk-importing tokens from another source</li>
<li>You want to automate token creation in Notion via script</li>
</ul>
<p>Run <code>npm run push</code> after editing your JSON, and the Notion database updates automatically.</p>
<h2 id="there-you-have-it!" tabindex="-1">There you have it!</h2>
<p>We've created a collaborative design token workflow that helps bring everyone together. Your team can now manage tokens in Notion's friendly interface, while developers get clean JSON for their builds. Everything stays in sync from one source of truth.</p>
<p>This foundation is pretty solid and should ready for expansion. You could add validation to catch errors early, use token references to avoid repetition, or organise by categories for larger sets. Going further you could add functionality that will allow the tokens to be imported into design tools liek Figma or Penpot.</p>
<p>For the complete working example with all scripts, <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/14-notion-design-tokens">check out the GitHub repository</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Underlining Links With CSS</title>
      <link href="https://www.alwaystwisted.com/articles/underlining-links-with-css.html"/>
      <updated>2026-02-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/underlining-links-with-css.html</id>
      <content type="html">
        <![CDATA[
        <p>Every time I need to style link underlines beyond the default browser styling, I find myself searching MDN for the same properties. I always think &quot;surely I know this by now?&quot; but then it slips my mind and off I go searching again. So, I've decided to write this down as my personal reference guide. Hopefully, it'll save you the same trip to the documentation!</p>
<p>For years, styling underlines on links meant either accepting the default look or hiding underlines entirely with <code>text-decoration: none;</code> and relying on other styling methods like borders or box-shadows to indicate interactivity. But CSS now gives us a whole set of <code>text-decoration</code> properties that let us get really specific about how our underlines should look and behave.</p>
<h2 id="the-text-decoration-properties" tabindex="-1">The Text Decoration Properties</h2>
<p>The &quot;modern approach&quot; to link underlines can use a set of individual <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration"><code>text-decoration</code> properties</a>. These properties give us granular control over every part of an underline.</p>
<p>Let's walk through each one.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>Historically, <code>text-decoration</code> let you choose the type of decoration (<code>none</code>, <code>underline</code>, <code>overline</code>, <code>line-through</code>), but you couldn't style it. The underline would always be the browser's default—solid, in the text color, with a fixed thickness. Now, with the individual <code>text-decoration</code> properties, you get control over the appearance. Using these properties with progressive enhancement ensures that all browsers should get a usable underline, while newer browsers get the enhanced styling.</p>
</div></div>
<h3 id="text-decoration" tabindex="-1"><code>text-decoration</code></h3>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration"><code>text-decoration</code></a> shorthand lets you set multiple underline properties in one declaration. For example:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline solid red 2px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>In this example, we're saying: add an underline, make it solid, color it red, and give it a thickness of 2 pixels.</p>
<h3 id="text-decoration-line" tabindex="-1"><code>text-decoration-line</code></h3>
<p>Use <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-line"><code>text-decoration-line</code></a> when you want to control what type of line appears. You've got a few options beyond just <code>underline</code>:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration-line</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can also use <code>overline</code> (line above the text), <code>line-through</code> (for strikethrough), <code>none</code> (no decoration), or even combine them like <code>underline overline</code> for multiple lines.</p>
<h3 id="text-decoration-color" tabindex="-1"><code>text-decoration-color</code></h3>
<p>Want your underlines to be a different color than your text? That's where <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-color"><code>text-decoration-color</code></a> comes in.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration-line</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-decoration-color</span><span class="token punctuation">:</span> #ea215a<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This is particularly useful when you want a more subtle or contrasting underline color. For instance, you might want muted underlines on dark text that pop on hover.</p>
<h3 id="text-decoration-style" tabindex="-1"><code>text-decoration-style</code></h3>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-style"><code>text-decoration-style</code></a> property controls how the line is drawn. Beyond the standard <code>solid</code> line, you can make it:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration-line</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-decoration-style</span><span class="token punctuation">:</span> wavy<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>A wavy underline can add personality, or you might use dotted for a more playful feel.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The available styles are: <code>solid</code> (default), <code>double</code>, <code>dotted</code>, <code>dashed</code>, and <code>wavy</code>.</p>
</div></div>
<h3 id="text-decoration-thickness" tabindex="-1"><code>text-decoration-thickness</code></h3>
<p>By default, browsers choose a thickness for underlines. But <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-thickness"><code>text-decoration-thickness</code></a> lets you be precise. You can use any length unit (px, em, rem) or percentages:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration-line</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-decoration-thickness</span><span class="token punctuation">:</span> 0.125em<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Using relative units like <code>em</code> is good here because the underline thickness can scale with the font size.</p>
<h3 id="text-underline-offset" tabindex="-1"><code>text-underline-offset</code></h3>
<p>One of the cool new properties, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-underline-offset"><code>text-underline-offset</code></a> controls the space between your text and the underline itself. This is great for giving underlines more &quot;breathing room&quot;:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-underline-offset</span><span class="token punctuation">:</span> 0.2em<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can also use negative values to bring the underline closer or above the baseline if you really wanted something unconventional.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The <code>text-underline-offset</code> property only affects underlines, not overlines or line-through decorations.</p>
</div></div>
<h3 id="text-underline-position" tabindex="-1"><code>text-underline-position</code></h3>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-underline-position"><code>text-underline-position</code></a> property is mostly useful if you're working with text that has descenders (like g, j, p, q, y). By default, browsers may skip over these descenders to keep underlines readable. You can force different behaviour:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-underline-position</span><span class="token punctuation">:</span> under<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The <code>under</code> value forces the underline to sit below all the descenders, giving you a consistent baseline.</p>
<h3 id="text-decoration-skip-ink" tabindex="-1"><code>text-decoration-skip-ink</code></h3>
<p>Speaking of descenders, <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration-skip-ink"><code>text-decoration-skip-ink</code></a> controls whether underlines skip over letter descenders:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">a</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
  <span class="token property">text-decoration-skip-ink</span><span class="token punctuation">:</span> auto<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Most of the time, <code>auto</code> is fine, it lets the browser skip over descenders for better readability. But if you want the underline to go through everything, use <code>none</code>.</p>
<h2 id="before-you-ship" tabindex="-1">Before You Ship</h2>
<p>A couple of important things to keep in mind:</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><code>text-underline-offset</code>, <code>text-underline-position</code>, and <code>text-decoration-skip-ink</code> are separate properties and aren't included in the <code>text-decoration</code> shorthand. If you use the shorthand, define them separately.</p>
</div></div>
<p>Also, when using the shorthand, one gotcha: setting <code>text-decoration</code> resets any previously set <code>text-decoration-thickness</code> unless you include the thickness value in the shorthand itself. It's easier to avoid the shorthand if you're using multiple properties.</p>
<p>Modern CSS text-decoration properties have solid support in current browsers, though some variations may need checking. Always test compatibility and think about progressive enhancement so that anyone on any browser gets as good an experience as possible.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Introducing The Design Tokens $extensions Checker</title>
      <link href="https://www.alwaystwisted.com/articles/introducing-the-extensions-checker.html"/>
      <updated>2026-02-02T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/introducing-the-extensions-checker.html</id>
      <content type="html">
        <![CDATA[
        <p>If you work with design tokens, you might find yourself needing to add an <a href="/articles/understanding-extensions-in-the-w3c-design-tokens-spec/"><code>$extensions</code></a> object for some specific use case. Then, down the line, other tools that consume your design tokens data might add their own extensions too. Before you know it, you're scrolling through nested metadata trying to figure out what extensions you actually have, who's using them, and whether you can clean anything up.</p>
<p>That's what I built the <a href="https://www.alwaystwisted.com/projects/dtm/extensions/"><strong>Design Tokens $extensions Checker</strong></a>. A quick way to see exactly what extensions are hiding in your design tokens.</p>
<!-- insert extensions-checker.jpg here -->
<p><img src="/images/articles/extensions-checker.jpg" alt="The Design Tokens Extensions Checker displaying the input data, examples of extensions, and output data highlighting the example found" loading="lazy" decoding="async"></p>
<h2 id="what-it-does" tabindex="-1">What it does</h2>
<p>Paste your design tokens data into the text area and it will extract every <code>$extensions</code> object it can find.</p>
<p>You should get:</p>
<ul>
<li>A full list of all extensions so you can see every namespace, property, and piece of metadata at a glance.</li>
<li>Clear visualisation with extensions grouped logically so you can spot patterns or duplicates.</li>
<li>Easy cleanup options that let you delete extensions individually or in bulk once you understand what you have.</li>
<li>A preview of your modified tokens showing the cleaned-up JSON ready to copy back into your workflow.</li>
</ul>
<h2 id="why-this-matters" tabindex="-1">Why this matters</h2>
<p>Here's the thing: <code>$extensions</code> is supposed to stay out of your way until you actually need it. But when you <em>do</em> need it — when you're auditing your token structure, migrating systems, or just trying to understand what metadata you're carrying around — it helps to see it all in one place.</p>
<p>Maybe there will be some PenPot data layered on top of Style Dictionary config information layered on top of team governance metadata. The JSON is valid and everything works, but visualizing it separately from the token values themselves makes it way easier to reason about.</p>
<h2 id="how-to-use-it" tabindex="-1">How to use it</h2>
<ol>
<li>Grab your design tokens JSON file and paste it into the text area.</li>
<li>Hit the Parse button to extract all extensions and display them.</li>
<li>Review what extensions you have, then delete ones you don't need individually or delete all of them at once.</li>
<li>Copy your cleaned-up tokens back, ready to use in your workflow.</li>
</ol>
<p>I created a sample tokens file so you can see what the output looks like without digging through your own files first.</p>
<h2 id="when-it's-useful" tabindex="-1">When it's useful</h2>
<p>This tool can be really useful if you're auditing what extensions you're actually using, migrating between different metadata systems, cleaning up bloated token files, or just curious what's hiding in your extensions.</p>
<p>Like <a href="/relicss">Relicss</a>, it runs entirely in your browser. Nothing gets sent anywhere. Your design tokens stay on your machine.</p>
<p><a href="/projects/dtm/extensions/">Grab it and give it a try</a>.</p>
<p>If you want to learn more about what <code>$extensions</code> can do and why they exist, check out <a href="/articles/understanding-extensions-in-the-w3c-design-tokens-spec/">Understanding $extensions in the W3C Design Tokens Spec</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Understanding $extensions in the Design Tokens Specification</title>
      <link href="https://www.alwaystwisted.com/articles/understanding-extensions-in-the-design-tokens-spec.html"/>
      <updated>2026-01-30T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/understanding-extensions-in-the-design-tokens-spec.html</id>
      <content type="html">
        <![CDATA[
        <p>One of the smart things in the <a href="https://www.designtokens.org/tr/2025.10/format/">W3C Design Tokens Community Group (DRCG) Design Tokens spec</a> is how it acknowledges something simple, no standard can anticipate every use case.</p>
<p>Instead of trying to force everything into the specification, they created <code>$extensions</code>. Essentially it's a deliberate, scoped escape hatch. You can add extra data to your tokens without breaking them or polluting the standard.</p>
<h2 id="what-is-%24extensions%3F" tabindex="-1">What is <code>$extensions</code>?</h2>
<p>Think of it like this.</p>
<p>Your design tokens follow the spec strictly. But, sometimes you need to attach metadata that falls outside of it, tool-specific configuration, governance info, version history, whatever. Instead of inventing your own properties (which will create chaos), <code>$extensions</code> creates a place to put all this stuff.</p>
<p>Here's the important bit: The content of <code>$extensions</code> is completely freeform.</p>
<p>The spec doesn't validate what's inside. It can be strings, numbers, booleans, objects, whatever your use case needs. The only constraint is that it must be valid in whatever format you're using (JSON, YAML, etc.).</p>
<p>This is by design.</p>
<p>The DTCG intentionally placed almost no constraints on what can go in here, recognising that trying to anticipate every use case is foolish, if not futile.</p>
<p>You can use it for:</p>
<ul>
<li>Tool-specific configuration: Figma sync IDs, Style Dictionary transforms</li>
<li>Team metadata: who owns this token, approval status, links to docs</li>
<li>Workflow annotations: version history, changelog, deprecation warnings</li>
<li>Experimental features: anything not yet standardised</li>
<li>Integration data: bridges between tools, AI metadata, accessibility info</li>
</ul>
<p>One key rule? Use reverse domain notation. Instead of <code>myData</code> or <code>myData.mySite.com</code>, use <code>com.yourcompany.featureName</code>. This eliminates naming collisions and keeps things organised.</p>
<h2 id="why-this-matters" tabindex="-1">Why this matters</h2>
<p>Without something like <code>$extensions</code>, teams could be tempted to just add custom metadata at the token level. You would see things like <code>_figmaId</code>, <code>vendor-config</code>, <code>customData</code> scattered through your token files.</p>
<p>It would be a mess.</p>
<p>With <code>$extensions</code>:</p>
<ol>
<li><strong>Your tokens stay clean</strong>: All the extra stuff lives in a designated place</li>
<li><strong>Tools ignore what they don't understand</strong>: A token can pass through multiple tools and not lose data, even if those tools don't know about each others' extensions</li>
<li><strong>No waiting for spec updates</strong>: Teams can try new approaches immediately instead of proposing, debating, and waiting for standardisation</li>
</ol>
<h2 id="real-world-examples" tabindex="-1">Real-world examples</h2>
<h3 id="tool-integration" tabindex="-1">Tool integration</h3>
<p>If you're syncing tokens between Figma and your codebase, you might want to store Figma's internal IDs:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"primary-blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#0066CC"</span><span class="token punctuation">,</span>
    <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"com.figma.tokens"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"styleId"</span><span class="token operator">:</span> <span class="token string">"S:abc123def"</span><span class="token punctuation">,</span>
        <span class="token property">"lastSynced"</span><span class="token operator">:</span> <span class="token string">"2026-01-28T10:30:00Z"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="team-governance" tabindex="-1">Team governance</h3>
<p>Or maybe your design system has approval workflows and you need to track who owns what:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"heading-large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"typography"</span><span class="token punctuation">,</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token comment">/* ... */</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"com.acme.governance"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"owner"</span><span class="token operator">:</span> <span class="token string">"design-system-team"</span><span class="token punctuation">,</span>
        <span class="token property">"approvedBy"</span><span class="token operator">:</span> <span class="token string">"jane.doe@acme.com"</span><span class="token punctuation">,</span>
        <span class="token property">"approvalDate"</span><span class="token operator">:</span> <span class="token string">"2026-01-15"</span><span class="token punctuation">,</span>
        <span class="token property">"usageGuidelines"</span><span class="token operator">:</span> <span class="token string">"https://docs.acme.com/tokens/heading-large"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="build-time-metadata" tabindex="-1">Build-time metadata</h3>
<p>Style Dictionary might need specific transforms for certain tokens:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing-md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
    <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"io.github.style-dictionary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"transforms"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"size/rem"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"platforms"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"web"</span><span class="token punctuation">,</span> <span class="token string">"ios"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="accessibility-data" tabindex="-1">Accessibility data</h3>
<p>You could even attach contrast ratios or WCAG conformance info. This is a good example of <em>computed or derived</em> metadata. The contrast ratio isn't inherent to the token itself, but depends on what you're comparing it against.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"text-body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#333333"</span><span class="token punctuation">,</span>
    <span class="token property">"$extensions"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"org.w3.wcag"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"contrastRatio"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"onWhite"</span><span class="token operator">:</span> <span class="token number">12.6</span><span class="token punctuation">,</span>
          <span class="token property">"onPrimaryBg"</span><span class="token operator">:</span> <span class="token number">4.8</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"level"</span><span class="token operator">:</span> <span class="token string">"AAA"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>These examples focus on token-level extensions (the most common case), but <code>$extensions</code> also works at group and root levels. Use whatever scope makes sense for your metadata.</p>
</div></div>
<h2 id="real-world-support" tabindex="-1">Real-world support</h2>
<p>The DTCG spec reached a stable version (2025.10) in October 2025, and adoption seems to be happening fast, although unevenly.</p>
<p>Figma announced native support at their 2025 Schema conference. You can now export variables as spec-compliant JSON and import them back. However, Figma's not preserving <code>$extensions</code> (yet). If you import a token file with extensions, they will get removed when you export them.</p>
<p>Penpot did it differently. They were the first design tool to natively implement the specification (working with <a href="https://tokens.studio">Tokens Studio</a>), including <code>$extensions</code> support. You can import and export tokens with custom extensions, and Penpot preserves what it doesn't understand, exactly how the specification intends.</p>
<p>Build tools are where things get interesting. Style Dictionary, Tokens Studio, and Terrazzo all have solid <code>$extensions</code> support out of the box.</p>
<p>But here's the thing.</p>
<p>The spec says tools should preserve extensions they don't understand, and not all of them are there yet. If your workflow relies on <code>$extensions</code> for important metadata, you need to know which tools will keep that data and which won't.</p>
<h2 id="what-not-to-put-in-%24extensions" tabindex="-1">What not to put in <code>$extensions</code></h2>
<p>Just because you <em>can</em> put something in extensions doesn't mean you should. Here's what to avoid:</p>
<ul>
<li><strong>Data that changes a token's meaning</strong>: This belongs in the core spec properties, not extensions</li>
<li><strong>Secrets or sensitive information</strong>: Token files are often committed to version control, so don't store API keys, credentials, or anything that shouldn't be in a repo</li>
<li><strong>Massive amounts of data</strong>: Keep your token files parseable and version-control friendly</li>
</ul>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><strong>Tools are free to ignore extensions entirely</strong>. A tool that only cares about the core spec can safely strip all <code>$extensions</code> and still have valid tokens. This is a feature, not a bug — it means your core token data is never held hostage by proprietary extensions.</p>
</div></div>
<h2 id="the-challenges" tabindex="-1">The challenges</h2>
<p>It's not perfect though. A few things to think about:</p>
<h3 id="file-bloat" tabindex="-1">File bloat</h3>
<p>Every extension you add makes your token files bigger. Larger files could mean slower parsing, bigger version control diffs, more overhead. You can manage this with smart tooling. Strip extensions for production builds, use compression, externalize large extension data, but it will require discipline and governance.</p>
<h3 id="fragmentation-risk" tabindex="-1">Fragmentation risk</h3>
<p>If teams all solve the same problems differently in their extensions, you would end up with incompatible ecosystems. One team uses <code>com.team1.metadata</code>, another uses <code>com.team2.metadata</code>, and suddenly migrating between them is painful.</p>
<p>The antidote? Document your extensions. Share them. When something proves valuable, perhaps propose it for standardisation. Your design system will work better when people aren't inventing in silos.</p>
<h3 id="discovery" tabindex="-1">Discovery</h3>
<p>There's no central registry of extensions (yet). If you want to know what extensions exist or how other teams handle something, you're basically having to reverse-engineer other peoples' token files. This will hopefully get better as the community matures.</p>
<h2 id="best-practices" tabindex="-1">Best practices</h2>
<p>If you're adding extensions to your tokens:</p>
<ul>
<li><strong>Document them</strong>: Include schemas, examples, and rationale</li>
<li><strong>Keep it optional</strong>: Never make extensions critical to understanding a token's actual value</li>
<li><strong>Version your extensions</strong>: If you change structure significantly, bump a version</li>
<li><strong>Think about preservation</strong>: If you're building a tool, always maintain extensions you don't understand</li>
<li><strong>Plan for obsolescence</strong>: Extensions can be a proving ground, not a forever home. When something is proven, consider proposing it for standardisation</li>
</ul>
<h2 id="the-bigger-picture" tabindex="-1">The bigger picture</h2>
<p><code>$extensions</code> represents a mature way of thinking about standards. It says: &quot;We're going to nail down what matters to everyone. For the rest, we'll create a clear, defined space where you can innovate without breaking things.&quot;</p>
<p>Too rigid, and the standard stifles innovation. Too loose, and you have chaos. I think this is a reasonable middle ground.</p>
<p>If you're working with design tokens, understanding how to use <code>$extensions</code> well should make your token files more flexible, more portable, and way more useful across different tools and workflows.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>I’ve been compiling my Sass wrong, for years</title>
      <link href="https://www.alwaystwisted.com/articles/ive-been-compiling-my-sass-wrong-for-years.html"/>
      <updated>2026-01-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/ive-been-compiling-my-sass-wrong-for-years.html</id>
      <content type="html">
        <![CDATA[
        <p>For years, I've been preprocessing Sass in my build pipeline without really thinking about how I was doing it. Every project would follow the same pattern: set up Sass, write a build script, and leave it alone. It worked. It was fast enough. I never questioned it.</p>
<p>That changed recently when I saw a deprecation warning in my build logs. It transpires, I've been using an API that's been obsolete for almost five years. And I didn't even know it.</p>
<h2 id="the-warning" tabindex="-1">The warning</h2>
<p>The warning was clear enough:</p>
<pre class="language-bash"><code class="language-bash">Deprecation Warning: The legacy JS API is deprecated and will be removed <span class="token keyword">in</span> Dart Sass <span class="token number">2.0</span>.0.</code></pre>
<p>I'd probably glanced over this warning a couple of times in recent weeks, but today it stopped me. I'm using <strong>Dart Sass</strong>. How was I possibly using a &quot;legacy&quot; API? I started digging and realised I've been clinging to <code>renderSync()</code> since my node-sass days.</p>
<h2 id="what-i-missed%2C-the-modern-api" tabindex="-1">What I missed, the modern API</h2>
<p>Back in late 2021, Dart Sass 1.45.0 introduced a fresh approach. Instead of <code>renderSync()</code>, the new API gave us:</p>
<ul>
<li><code>compile()</code> and <code>compileAsync()</code> for compiling files</li>
<li><code>compileString()</code> and <code>compileStringAsync()</code> for compiling strings directly</li>
</ul>
<p>These aren't just renamed methods. They're a proper redesign with better performance, cleaner syntax, proper Promise support instead of callbacks, and better TypeScript support.</p>
<h3 id="the-performance-bump" tabindex="-1">The performance bump</h3>
<p>The real surprise is the performance gain. When you use the modern API with <code>sass-embedded</code> (the faster Dart Sass implementation), you could be looking at <strong>5-10x faster</strong> compilation. That's not a marginal improvement. For projects with hundreds of imports, that's the difference between a build taking 30 seconds and 3 seconds.</p>
<p>Why? The old API was designed for the node-sass era, before modern Sass had its own compiler. The new API was built from the ground up for Dart Sass.</p>
<h2 id="migrating-the-code" tabindex="-1">Migrating the code</h2>
<p>Here's what the actual migration looks like. My old code using the legacy API:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sass <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sass'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Synchronous file compilation</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">renderSync</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">outputStyle</span><span class="token operator">:</span> <span class="token string">'compressed'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">sourceMap</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token literal-property property">outFile</span><span class="token operator">:</span> <span class="token string">'dist/main.css'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'dist/main.css'</span><span class="token punctuation">,</span> result<span class="token punctuation">.</span>css<span class="token punctuation">)</span><span class="token punctuation">;</span>
fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'dist/main.css.map'</span><span class="token punctuation">,</span> result<span class="token punctuation">.</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The modern equivalent:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sass <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sass'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Synchronous file compilation</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span><span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">style</span><span class="token operator">:</span> <span class="token string">'compressed'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">sourceMap</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'dist/main.css'</span><span class="token punctuation">,</span> result<span class="token punctuation">.</span>css<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>result<span class="token punctuation">.</span>sourceMap<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span><span class="token string">'dist/main.css.map'</span><span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>sourceMap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The key differences took me a moment to adjust to:</p>
<ol>
<li><strong>The file path is the first argument</strong> - Not buried in an options object. Much cleaner.</li>
<li><strong><code>outputStyle</code> is now <code>style</code></strong> - Just a property rename.</li>
<li><strong>No <code>outFile</code> needed</strong> - The modern API doesn't write files for you. You get back the CSS and source map, then handle the file writing yourself.</li>
<li><strong>CSS is already a string</strong> - No more calling <code>.toString()</code> on a Buffer.</li>
<li><strong>Source maps are objects</strong> - Not strings, so you stringify them when writing.</li>
</ol>
<h3 id="compiling-strings-instead-of-files" tabindex="-1">Compiling strings instead of files</h3>
<p>There are scenarios where you need to compile Sass without reading from a file. Build tools might construct Sass strings on-the-fly, or you could have a CMS that lets content editors define variables. Maybe you're generating a theme dynamically based on user input. In those cases, you're compiling strings directly:</p>
<p><strong>Old way:</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">renderSync</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token string">'$primary: #333; body { color: $primary; }'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">outputStyle</span><span class="token operator">:</span> <span class="token string">'compressed'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><strong>New way:</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">compileString</span><span class="token punctuation">(</span><span class="token string">'$primary: #333; body { color: $primary; }'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">style</span><span class="token operator">:</span> <span class="token string">'compressed'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="going-async" tabindex="-1">Going async</h3>
<p>One of the nice wins is async/await support. The old callback-based approach looked like this:</p>
<pre class="language-javascript"><code class="language-javascript">sass<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">(</span><span class="token parameter">err<span class="token punctuation">,</span> result</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>css<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the modern API:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">compileSass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token keyword">await</span> sass<span class="token punctuation">.</span><span class="token function">compileAsync</span><span class="token punctuation">(</span><span class="token string">'styles/main.scss'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>css<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">compileSass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Much cleaner with async/await. If you're using this in a build tool or automation script, it's much more natural to work with.</p>
<h3 id="custom-functions-and-importers" tabindex="-1">Custom functions and importers</h3>
<p>Custom functions let you extend Sass with your own logic. You might need a function to calculate responsive sizes, generate colour variants, or perform calculations that Sass's built-in functions don't handle. Importers let you override how Sass finds and loads files (useful if you're loading Sass from a database, a package manager, or a custom file system). These are more advanced use cases, but if you're doing either, the API changed significantly.</p>
<p>The old way with custom functions:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sass <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sass'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">renderSync</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">functions</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token string-property property">'double($n)'</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">n<span class="token punctuation">,</span> done</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">done</span><span class="token punctuation">(</span>sass<span class="token punctuation">.</span>types<span class="token punctuation">.</span><span class="token function">Number</span><span class="token punctuation">(</span>n<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">,</span> n<span class="token punctuation">.</span><span class="token function">getUnit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The modern approach:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sass <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sass'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> result <span class="token operator">=</span> sass<span class="token punctuation">.</span><span class="token function">compile</span><span class="token punctuation">(</span><span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">functions</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token string-property property">'double($n)'</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">args</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> n <span class="token operator">=</span> args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">assertNumber</span><span class="token punctuation">(</span><span class="token string">'n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">sass<span class="token punctuation">.</span>SassNumber</span><span class="token punctuation">(</span>n<span class="token punctuation">.</span>value <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">,</span> n<span class="token punctuation">.</span>numeratorUnits<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The modern API uses a more robust system. It's less magical and more explicit, which honestly feels better.</p>
<h2 id="what-about-build-tools%3F" tabindex="-1">What about build tools?</h2>
<p>If you're using a build tool like webpack, Vite, or gulp, check whether they've updated their Sass integration. Most have, but support varies:</p>
<p><strong>sass-loader</strong> (for webpack) supports the modern API in v14+ if you set <code>api: 'modern-compiler'</code>. That option gives you the performance bump I mentioned earlier.</p>
<p><strong>Vite</strong> already uses the modern API by default, so if you're on a recent version, you're already getting the benefits.</p>
<p><strong>gulp-sass</strong> is still working on full migration support, though it's improving.</p>
<p>If you're configuring sass-loader, the setup is straightforward:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'sass-loader'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">api</span><span class="token operator">:</span> <span class="token string">'modern-compiler'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">implementation</span><span class="token operator">:</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'sass'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>That one option can make a noticeable difference in your build times if you've got a lot of Sass to process.</p>
<h2 id="should-you-update%3F" tabindex="-1">Should you update?</h2>
<p>Yes.</p>
<p>Here's why.</p>
<p><a href="https://github.com/sass/dart-sass/milestone/3">Dart Sass 2.0.0 is coming</a>, and the legacy API will be removed entirely. If you're still using <code>renderSync()</code> and <code>render()</code>, your build will break. There's no safety net, no deprecation option, no workaround.</p>
<p>Beyond that, the performance gains are real. If you're compiling Sass regularly as part of your workflow, cutting build times by 80-90% is worth the effort. The modern API is genuinely better to work with too.</p>
<p>If you do need time to migrate, you can suppress the warnings temporarily:</p>
<pre class="language-javascript"><code class="language-javascript">sass<span class="token punctuation">.</span><span class="token function">renderSync</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">file</span><span class="token operator">:</span> <span class="token string">'styles/main.scss'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">silenceDeprecations</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'legacy-js-api'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>But don't rely on that, you'll be forced to update eventually anyway.</p>
<h2 id="the-lesson" tabindex="-1">The lesson</h2>
<p>I've only just noticed the warnings in my build logs recently. I could have accidentally spent years skipping it thinking “It works&quot; was enough. Sometimes what works is just outdated, and you don't realise it until something forces you to look at it properly.</p>
<p>In this case, I didn’t know how much of a performance benefit I would be leaving on the table. I was using an API that had been superseded by something better, faster, and cleaner. All because I never upgraded a function call from (checks notes) 2015.</p>
<p>The <code>renderSync()</code> API served a purpose. It got Sass running in Node in the first place. But it's time to move on. The modern API isn't just a rename, it's a real improvement that makes your builds faster and your code cleaner.</p>
<p>So I've updated my build scripts. Compared to migrating from <code>@import</code> to <code>@use</code> and <code>@forward</code>, it didn't take long. The deprecation warning is gone and my builds are faster.</p>
<p>I probably should have done this when it came out five years ago, but at least I did it now.</p>
<p>If you're seeing that same deprecation warning in your logs, now is a good time to update yours too.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Introducing ReliCSS: A Tool for Front-End Archaeology</title>
      <link href="https://www.alwaystwisted.com/articles/introducing-relicss-a-tool-for-front-end-archaeology.html"/>
      <updated>2026-01-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/introducing-relicss-a-tool-for-front-end-archaeology.html</id>
      <content type="html">
        <![CDATA[
        <p>As a contracting front-end developer and Design Systems consultant, I don't always get to work on new things.</p>
<p>Sometimes I work within codebases. Sometimes alongside them. Sometimes these codebases are years and years old.</p>
<p>When you dive into these projects, you're not just reading code, you're excavating years of decisions, technological limitations, and creative workarounds from days gone by. Over the last decade, I've called this Front-End Archaeology.</p>
<h2 id="the-art-of-excavation" tabindex="-1">The Art of Excavation</h2>
<p>When I encounter a clearfix hack, I’m looking at a time when layout engines couldn't contain floated elements. When I see a &quot;doubled float margin bug&quot; fix, I’m witnessing “the scars” left by Internet Explorer 6. Every specific vendor prefix, every browser hack, and every strange <code>!important</code> rule tells a story of a developer fighting against the constraints of their time to ship a working product.</p>
<p>It’s easy to look at old code and judge it by modern standards, but Front-End Archaeology requires empathy and curiosity. It asks not just &quot;how do I delete this?&quot; but &quot;why was this necessary?&quot; and &quot;what can we learn from it?&quot;</p>
<p>Front-End Archaeology can take time. Identifying these artifacts manually requires deep historical knowledge of browser quirks that many modern developers (thankfully) never had to learn. That’s where tooling comes in.</p>
<h2 id="unearthing-history-with-relicss" tabindex="-1">Unearthing History with ReliCSS</h2>
<p>I've built a tool to help with this archaeological quest: <a href="https://www.alwaystwisted.com/relicss/">ReliCSS</a>.</p>
<p><img src="/images/articles/ReliCSS-interface-screenshot.jpg" alt="The ReliCSS interface showing the CSS scanner with code input area and results displaying severity levels for browser hacks" loading="lazy" decoding="async"></p>
<p>ReliCSS is an assistant during &quot;the dig&quot;. It's a dedicated scanner that analyses CSS to identify historical artifacts or &quot;browser hacks&quot; that can riddle older stylesheets.</p>
<p>Whether you're auditing a legacy codebase for a refactor or just curious about the history in your project's stylesheets, ReliCSS helps you spot “the ghosts in the machine”.</p>
<h3 id="how-it-works" tabindex="-1">How It Works</h3>
<p>Currently you can paste your CSS into the ReliCSS and it will parse it and highlight any browser hacks it finds.</p>
<p>For every “hack”, ReliCSS shows you the browser target, the context, and some suggestions to modernise it. ReliCSS assigns a <strong>Severity Level</strong> to help you prioritise what to refactor, and what you could or should remove:</p>
<ul>
<li><strong>High Severity:</strong> True “fossils”. Hacks for (now) unsupported browsers (IE6/7) or “dangerous” techniques. High-risk, obsolete, should be first targets for removal.</li>
<li><strong>Medium Severity:</strong> The middle ground. Hacks for older unsupported browsers (IE8-10). They work but they're fragile. Hacks to review to see if they're still relevant foryour actual users.</li>
<li><strong>Low Severity:</strong> Modern artifacts. Usually vendor prefixes (-webkit-, -moz-). Safe mostly, but better handled by automated tools like Autoprefixer. They're an opportunity to improve your build process.</li>
</ul>
<p>I’ve built ReliCSS so it runs entirely in the browser, with contractors and consultants in mind who could be working with sensitive client code. When you click &quot;Scan CSS,&quot; the analysis happens in the browser. No code gets sent to a server or anywhere else You can safely paste CSS without worrying about data leaks.</p>
<h2 id="the-roadmap%3A-future-excavation-tools" tabindex="-1">The Roadmap: Future Excavation Tools</h2>
<p>As mentioned, right now, ReliCSS works by pasting CSS directly. But I am looking at things that can beed added and improved. Here's what's coming:</p>
<ul>
<li><strong>Drag &amp; Drop Uploads:</strong> Drop a .css file directly into the tool for instant scanning.</li>
<li><strong>URL Fetching:</strong> Point ReliCSS at a live stylesheet and let it pull the artifacts.</li>
<li><strong>Command Line Interface (CLI):</strong> This is “the big one”. I'm working on bringing ReliCSS to your terminal. You'll be able to script the excavation process, integrate these checks into your build pipelines or local dev environments, catch hacks before they get buried again.</li>
</ul>
<h2 id="from-archaeology-to-modernisation" tabindex="-1">From Archaeology to Modernisation</h2>
<p>Front-end archaeology isn't just about admiring the ruins. It's about building on top of them safely. ReliCSS bridges the gap between the past and the present. It helps you confidently distinguish between load-bearing code and historical cruft.</p>
<p>By identifying which parts of your CSS exist only to support a 2006 browser, you can make informed decisions about what to keep, refactor, or delete. It can turn the daunting task of refactoring legacy CSS into an actual learning experience about web history.</p>
<p>If you find yourself staring at a stylesheet that looks like it survived the browser wars, give <a href="https://www.alwaystwisted.com/relicss/">ReliCSS</a> a try. You might learn something about where it came from and have an easier time getting it to where you want it to go.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 13) - Generating Utility Classes from Design Tokens using Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-13.html"/>
      <updated>2025-11-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-13.html</id>
      <content type="html">
        <![CDATA[
        <p>This article shows a practical pattern for generating utility classes in CSS I’ve used in one form or another since 2016. Utility classes can give us a fast, consistent way to apply design system values in markup, without sprinkling hard‑coded styles across your project. As I discussed in my article on <a href="https://www.alwaystwisted.com/articles/creating-design-system-friendly-snowflakes-with-utility-classes">Creating Design System Friendly Snowflakes with Utility Classes</a>, utility classes can really help offer a middle ground between rigid components and completely custom CSS.</p>
<p>By generating utility classes directly from design tokens, we ensure that even any “one-off designs” stay consistent with our design system's values. If a design needs a specific spacing or colour that exists in our tokens, we can use a utility class rather than writing custom CSS with hard-coded values.</p>
<h2 id="defining-our-design-tokens" tabindex="-1">Defining Our Design Tokens</h2>
<p>To get things going, let’s define some design tokens for colour, spacing, and typography.</p>
<h3 id="colours" tabindex="-1">Colours</h3>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#f00"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff4d4d"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff9999"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#66b3ff"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#99ccff"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"green"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#28a745"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#66d69f"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#99e6b3"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="spacing" tabindex="-1">Spacing</h3>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.25rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.75rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"600"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"3rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="typography" tabindex="-1">Typography</h3>
<p>I’m going to split the examples for typography tokens into three separate files: <code>font-size.tokens</code>, <code>font-weight.tokens</code>, and <code>font-family.tokens</code>. This separation makes sense because font sizes, weights, and families often change at different rates (sizes might need frequent adjustments, while families rarely change), smaller, more focused files are easier to navigate and update rather than one large typography file, and we might decide to only generate utilities for sizes and weights but not families, for example.</p>
<h4 id="font-size" tabindex="-1">Font Size</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.75rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.875rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.125rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.25rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"600"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.5rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.75rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"800"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2rem"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="font-weight" tabindex="-1">Font Weight</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"200"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"500"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"700"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="font-family" tabindex="-1">Font Family</h4>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Arial, sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Consolas, monospace"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="utility-class-generation-script" tabindex="-1">Utility Class Generation Script</h2>
<p>When generating utility classes with Style Dictionary, how we structure our config or build script can make a real difference to how maintainable and scalable our setup becomes. I'm going to show two approaches. First, keeping everything in our ⁠build.js file, and then secondly, extracting the configuration into a separate ⁠utilities.js file.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for spacing utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-spacing'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> utilities <span class="token operator">=</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-top'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-top'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-right'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-right'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-bottom'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-bottom'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-left'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-left'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-top'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-top'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-right'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-right'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-bottom'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-bottom'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-left'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-left'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Spacing Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilities<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'spacing'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for colour utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> utilities <span class="token operator">=</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'background-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'border'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'border-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Colour Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilities<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> colorName <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>colorName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for font-size utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-size'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Size Utilities */\n\n'</span><span class="token punctuation">;</span>

    dictionary<span class="token punctuation">.</span>allTokens
      <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'size'</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> size <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">font-size--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  font-size: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for font-weight utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-weight'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Weight Utilities */\n\n'</span><span class="token punctuation">;</span>

    dictionary<span class="token punctuation">.</span>allTokens
      <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'weight'</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> weight <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">font-weight--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>weight<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  font-weight: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for font-family utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-family'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Family Utilities */\n\n'</span><span class="token punctuation">;</span>

    dictionary<span class="token punctuation">.</span>allTokens
      <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'family'</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> family <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">font-family--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>family<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  font-family: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build configuration</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'src/tokens/base/**/*.tokens'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">preprocessors</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens-studio'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-spacing.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-spacing'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-color.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-size.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-size'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-weight.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-weight'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-family.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-family'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="understanding-the-custom-formats" tabindex="-1">Understanding the Custom Formats</h3>
<p>Let's break down how <code>StyleDictionary.registerFormat()</code> works using the colour utilities as an example:</p>
<pre class="language-javascript"><code class="language-javascript">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// ... format logic</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p><code>StyleDictionary.registerFormat()</code> tells Style Dictionary &quot;I want to create a new output format that we can use when generating files.&quot; The <code>name</code> property (<code>’css/utility-color'</code> in this case) is the unique identifier for our format. Later, when we configure the build, we reference this <code>name</code> to tell Style Dictionary which format to use for a specific file—in our case, we use <code>format: 'css/utility-color'</code> in the files array to connect this custom format to the <code>utilities-color.css</code> output file.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-color.css'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span> <span class="token comment">// References the name here</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Here in the build configuration, we reference the format by its name (⁠<code>’css/utility-color'</code>) to tell Style Dictionary which custom format to use when generating the <code>⁠utilities-color.css</code> file.</p>
<h3 id="inside-the-format-function%3A" tabindex="-1">Inside the format function:</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Define what we want to generate</span>
  <span class="token keyword">const</span> utilities <span class="token operator">=</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'background-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'border'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'border-color'</span> <span class="token punctuation">}</span>
  <span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token comment">// Start building the CSS output as a string</span>
  <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Colour Utilities */\n\n'</span><span class="token punctuation">;</span>

  <span class="token comment">// Loop through each utility type (text, background, border)</span>
  utilities<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">util</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// Access all tokens and filter to only colour tokens</span>
    dictionary<span class="token punctuation">.</span>allTokens
      <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token parameter">token</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">token</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token comment">// Build the class name from the token path, token.path might be ['color', 'red', '500']. slice(1) removes 'color', leaving ['red', '500']. join('-') creates 'red-500'</span>
        <span class="token keyword">const</span> colorName <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>colorName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

        <span class="token comment">// Generate the CSS rule</span>
        output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Return the complete CSS string</span>
  <span class="token keyword">return</span> output<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>There are a few key things to understand here. ⁠<code>dictionary.allTokens</code> is an array containing every token from our files after they've been processed. Each token has a <code>⁠path</code> property representing the structure of our token. For example, a token at ⁠<code>color.red.500</code> has the path ⁠[<code>’color', 'red', '500'</code>]. The <code>⁠token.$value</code> property contains the value (e.g., ⁠<code>#f00</code>). What’s returned becomes the content for the generated file(s).</p>
<p>When Style Dictionary runs, it loads all of the tokens found in <code>⁠src/tokens/base/**/*.tokens</code>, it looks for the file configuration that uses <code>⁠format: 'css/utility-color'</code>, calls the custom format function, and takes the returned information and generates ⁠<code>build/css/utilities-color.css</code>.</p>
<p>This will create a CSS file like:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Colour Utilities */</span>

<span class="token selector">.text-red-500</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #f00<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.text-red-400</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #ff4d4d<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.bg-blue-500</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* ... and so on */</span></code></pre>
<h2 id="improving-the-build-script-with-a-separate-config-file" tabindex="-1">Improving the build script with a separate config file</h2>
<p>Even with only creating utility classes the build.js is starting to feeling crowded, so we’re going to ‘extract’ the configuration data into a separate file. This separates <em>what</em> utilities we want from <em>how</em> they're generated.</p>
<p>Create a <code>config/utilities.js</code> file</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> utilityConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">spacing</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-top'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-top'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-right'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-right'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-bottom'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-bottom'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'padding-left'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'padding-left'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-top'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-top'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-right'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-right'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-bottom'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-bottom'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'margin-left'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'margin-left'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'background-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'border'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'border-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">fontSize</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'font-size'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'font-size'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">fontWeight</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'font-weight'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'font-weight'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">fontFamily</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'font-family'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'font-family'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>With this file now available it’s time to update the <code>build.js</code> to import it and use it:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> utilityConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./config/utilities.js'</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for spacing utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-spacing'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Spacing Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilityConfig<span class="token punctuation">.</span>spacing<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'spacing'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for colour utilities</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Colour Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilityConfig<span class="token punctuation">.</span>color<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> colorName <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'--'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>colorName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-size'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Size Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilityConfig<span class="token punctuation">.</span>fontSize<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'size'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> size <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-weight'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Weight Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilityConfig<span class="token punctuation">.</span>fontWeight<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
          <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'weight'</span>
        <span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> weight <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>weight<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-font-family'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Font Family Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilityConfig<span class="token punctuation">.</span>fontFamily<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
          <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'font'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'family'</span>
        <span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> family <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>family<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build configuration</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'src/tokens/base/**/*.tokens'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">preprocessors</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens-studio'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-spacing.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-spacing'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-color.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-size.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-size'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-weight.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-weight'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'utilities-font-family.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/utility-font-family'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="what%E2%80%99s-changed-here%3F" tabindex="-1">What’s changed here?</h3>
<p>As mentioned above, the difference between these two approaches is where the utility definitions are defined. In the first approach, they are defined directly inside each format function.</p>
<pre class="language-javascript"><code class="language-javascript">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> utilities <span class="token operator">=</span> <span class="token punctuation">[</span>
      <span class="token comment">// Defined here, inside the function</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'background-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'border'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'border-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    utilities<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token comment">// ... generate CSS</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>By separating the configuration for the utilities we are importing them from the external file into the <code>build.js</code> script</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> utilityConfig <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./config/utilities.js'</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// No utilities array defined here</span>

    utilityConfig<span class="token punctuation">.</span>color<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token comment">// Using imported config instead</span>
      <span class="token comment">// ... generate CSS (same logic as before)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The format function itself does exactly the same work, looping through utilities and generating CSS. The only difference is the source of the utility definitions. Instead of hardcoding them in the build script, we're pulling them from <code>⁠utilityConfig.color</code>, which comes from our separate <code>config/utilities.js</code> configuration file.</p>
<p>This way when we want to add a new utility (say, <code>⁠.outline-red-500</code> for <code>⁠outline-color</code>), we edit ⁠<code>config/utilities.js</code> and add ⁠<code>{ prefix: 'outline', property: 'outline-color' }</code> to the ⁠colour array. The build script doesn't need to change at all and should automatically pick up the new definitions and generate the relevant utility classes.</p>
<h2 id="comparing-the-approaches" tabindex="-1">Comparing the Approaches</h2>
<p>Starting with everything in ⁠<code>build.js</code> can work well because everything is visible in one file and we can see exactly what's happening. There are no additional files to manage or import, making it perfect for getting started or for smaller projects. It's also easy to debug since all the logic is in one place.</p>
<p>However, this approach could fall short as the project grows. As we add more utility types, other formats (<code>.scss</code>, <code>.js</code> that are needed for the work the file can quickly grow, and the utility definitions could get mixed with the generation logic. If we wanted to reuse this setup in another project, we might need to copy the entire file, and making changes to utility definitions requires editing the build script itself.</p>
<p>Moving to a ‘separated configuration’ can improve things considerably. The configuration for the utility classes is separated from logic, making it easier to see what we’re going to be generating. Our ⁠build.js should become cleaner and more focused on only the generation process. The configuration file could be shared across projects and non-developers can more easily make changes to utility definitions without touching the build logic.</p>
<p>However, there are some things to consider with this approach. We will now have (at least) two files to maintain instead of one, the build script still needs to register each format individually, and we are still repeating similar logic for each utility type. But for most projects, these trade-offs are worth the improved organisation and maintainability.</p>
<h3 id="generated-output" tabindex="-1">Generated Output</h3>
<p>Regardless of which configuration approach we choose, the output remains the same. Here's what gets generated:</p>
<h4 id="utilities-spacing.css" tabindex="-1">utilities-spacing.css</h4>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Spacing Utilities */</span>

<span class="token selector">.padding--100</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.padding--200</span> <span class="token punctuation">{</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.padding-top--100</span> <span class="token punctuation">{</span>
  <span class="token property">padding-top</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.margin-top--400</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* ... more utilities */</span></code></pre>
<h4 id="utilities-color.css" tabindex="-1">utilities-color.css</h4>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Colour Utilities */</span>

<span class="token selector">.text-red--500</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #f00<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.bg-blue--400</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #66b3ff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.border-green--300</span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> #99e6b3<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* ... more utilities */</span></code></pre>
<h4 id="utilities-font-size.css" tabindex="-1">utilities-font-size.css</h4>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Font Size Utilities */</span>

<span class="token selector">.font-size--100</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.font-size--300</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.font-size--600</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* ... more utilities */</span></code></pre>
<h2 id="generating-semantic-utility-classes" tabindex="-1">Generating Semantic Utility Classes</h2>
<p>While the utilities we've generated so far use the raw token names (like <code>.text-500</code> or <code>.background-blue-400</code>), it could be better if we generated more semantic utility classes that better communicate intent of our design decisions.</p>
<p>For example, if we have semantic colour tokens file like:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"semantic"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"danger"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"success"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.green.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>We could create a separate format that generates semantic utilities:</p>
<pre class="language-javascript"><code class="language-javascript">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'css/utility-semantic-color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> utilities <span class="token operator">=</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'background'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'background-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span> <span class="token literal-property property">prefix</span><span class="token operator">:</span> <span class="token string">'border'</span><span class="token punctuation">,</span> <span class="token literal-property property">property</span><span class="token operator">:</span> <span class="token string">'border-color'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">let</span> output <span class="token operator">=</span> <span class="token string">'/* Semantic Colour Utilities */\n\n'</span><span class="token punctuation">;</span>

    utilities<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">util</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      dictionary<span class="token punctuation">.</span>allTokens
        <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
          <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'color'</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token string">'semantic'</span>
        <span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> semanticName <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">[</span>token<span class="token punctuation">.</span>path<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
          <span class="token keyword">const</span> className <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>prefix<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>semanticName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          output <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>className<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n  </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>util<span class="token punctuation">.</span>property<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>$value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;\n}\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> output<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This would generate utilities like:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.text--primary</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.background--danger</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #f00<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.border--success</span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> #28a745<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This approach can give us both the flexibility of low-level utilities (<code>.text-500</code>) and the clarity of semantic utilities (<code>.text-primary</code>).</p>
<p>Generating utility classes from our design tokens can help ‘bridge the gap’ between our design system and the potential fast-paced, real-world needs of building interfaces.</p>
<p>By automating this process with Style Dictionary, we can ensure that utility classes should stay in sync with our tokens. When we update a token value, the utility classes can be automatically updated. Teams are now constrained to use system values even for one-off designs, keeping everything aligned and being able to create things that are ‘of the Design System’ but not necessarily something that will ever become something that is ‘from the Design System’.</p>
<p>You can find the code for this article in <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/13-generating-utility-classes">this branch of the github repo</a> for this series.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Few Useful Web Development Bookmarklets</title>
      <link href="https://www.alwaystwisted.com/articles/a-few-web-developer-bookmarklets.html"/>
      <updated>2025-10-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-few-web-developer-bookmarklets.html</id>
      <content type="html">
        <![CDATA[
        <p>I started creating a few bookmarklets (small JavaScript snippets saved as browser bookmarks) when working with a client which involved some 'front-end archeology' looking at a codebase that was 15 years mature and has been worked on since. These tools helped me quickly understand the structure, dependencies, and technical debt without having to dive deep into the codebase first.</p>
<p>The bookmarklets I've created focus on some common web development inspection tasks that aren't always easy to accomplish with standard browser developer tools:</p>
<ol>
<li>Toggling between JavaScript and non-JavaScript states.</li>
<li>Finding inline CSS in the document.</li>
<li>Identifying elements with inline styles.</li>
<li>Detecting third-party resources.</li>
<li>Highlighting design system component usage.</li>
</ol>
<p>Each of these addresses specific challenges I faced when trying to understand and document legacy front-end code. They've proven particularly valuable when auditing sites with multiple developers' contributions over many years, revealing patterns and issues that could remain hidden.</p>
<p>These bookmarklets don't attempt to replace comprehensive developer tools, but rather complement them by providing quick insights for specific front-end investigation.</p>
<h2 id="js%2Fno-js-toggle" tabindex="-1">JS/No-JS Toggle</h2>
<p>This bookmarklet toggles between <a href="https://www.google.com/search?client=safari&amp;rls=en&amp;q=paul+irish+no-js&amp;ie=UTF-8&amp;oe=UTF-8">the js and no-js classes on the HTML element</a>. It's useful for testing how your site behaves with and without JavaScript enabled.</p>
<p><a href="javascript:(function(){var htmlElement=document.documentElement;if(htmlElement.classList.contains('js')){htmlElement.classList.remove('js');htmlElement.classList.add('no-js');}else{htmlElement.classList.remove('no-js');htmlElement.classList.add('js');}})();">No No No No JS</a></p>
<h2 id="inline-css-inspector" tabindex="-1">Inline CSS Inspector</h2>
<p>This bookmarklet displays all inline CSS styles in the document head and style blocks in the page, along with line numbers and formatting.</p>
<p><a href="javascript:(function(){var d=document;var styles=Array.from(d.head.getElementsByTagName('style')).filter(s=>!s.hasAttribute('data-styled')&&!s.hasAttribute('data-emotion'));var c=d.createElement('div');c.style.cssText='position:fixed!important;top:0!important;left:0!important;right:0!important;z-index:9999!important;background:#fff!important;color:#000!important;padding:15px!important;border-bottom:2px solid #000!important;max-height:80vh!important;overflow:auto!important;font:14px Arial!important;box-shadow:0 2px 10px rgba(0,0,0,0.3)!important;';var html='<h3 style=\'margin:0 0 15px!important;font:bold 18px Arial!important;color:#000!important;\'>Inline CSS in HEAD</h3>';if(styles.length===0){html+='<div style=\'padding:10px!important;background:#f5f5f5!important;color:#000!important;border-left:3px solid #f33!important;\'>No inline CSS found in the HEAD element.</div>';}else{html+='<div style=\'margin-bottom:10px!important;color:#000!important;\'>Found <strong>'+styles.length+'</strong> style blocks:</div>';styles.forEach(function(style,index){var cssText=style.textContent.trim().replace(/}/g,'}\n').replace(/{/g,' {\n  ').replace(/;/g,';\n  ');html+='<div style=\'margin:10px 0!important;padding:10px!important;background:#f5f5f5!important;border:1px solid #ddd!important;border-radius:3px!important;\'><div style=\'color:#06a!important;font:bold 14px monospace!important;margin-bottom:5px!important;\'>Style Block #'+(index+1)+' <span style=\'color:#777!important;font-weight:normal!important;font-size:12px!important;\'>('+cssText.length+' characters)</span></div><pre style=\'margin:0!important;padding:8px!important;background:#fff!important;color:#333!important;font:13px monospace!important;overflow:auto!important;white-space:pre-wrap!important;border:1px solid #eee!important;max-height:300px!important;\'>'+cssText.replace(/</g,'&lt;').replace(/>/g,'&gt;')+'</pre></div>';});}html+='<div id=\'inline-css-close-btn\' style=\'position:absolute!important;top:10px!important;right:10px!important;background:#f33!important;color:#fff!important;border:none!important;padding:5px 10px!important;border-radius:3px!important;cursor:pointer!important;\'>Close</div>';c.innerHTML=html;d.body.appendChild(c);document.getElementById('inline-css-close-btn').addEventListener('click',function(){c.remove();});})();">Inline CSS Inspector</a></p>
<p><img src="/images/bookmarklets/css.png" alt="a screenshot showing results of this bookmarklet" loading="lazy" decoding="async"></p>
<h2 id="inline-element-styles-inspector" tabindex="-1">Inline Element Styles Inspector</h2>
<p>This bookmarklet scans the entire page for HTML elements that have inline ⁠style attributes and displays a comprehensive report.</p>
<p><a href="javascript:(function(){var d=document;var elements=Array.from(d.querySelectorAll('*')).filter(function(el){return el.hasAttribute('style')&&el.getAttribute('style').trim()!=='';});var c=d.createElement('div');c.style.cssText='position:fixed!important;top:0!important;left:0!important;right:0!important;z-index:9999!important;background:#fff!important;color:#000!important;padding:15px!important;border-bottom:2px solid #000!important;max-height:80vh!important;overflow:auto!important;font:14px Arial!important;box-shadow:0 2px 10px rgba(0,0,0,0.3)!important;';var h='<h3 style=\'margin:0 0 15px!important;font:bold 18px Arial!important;color:#000!important;\'>Inline Style Inspector</h3>';if(elements.length===0){h+='<div style=\'padding:10px!important;background:#f5f5f5!important;color:#000!important;border-left:3px solid #f33!important;\'>No elements with inline styles found on this page.</div>';}else{h+='<div style=\'margin-bottom:10px!important;color:#000!important;\'>Found <strong>'+elements.length+'</strong> elements with inline styles:</div>';for(var i=0;i<elements.length;i++){var el=elements[i];var tag=el.tagName.toLowerCase();var identifier='';if(el.id)identifier+=' id=\''+el.id+'\'';if(el.className)identifier+=' class=\''+el.className+'\'';var domPath=[];var currentEl=el;var depth=0;while(currentEl&&currentEl!==document.body&&domPath.length<3){var name=currentEl.tagName.toLowerCase();if(currentEl.id)name+='#'+currentEl.id;domPath.unshift(name);currentEl=currentEl.parentElement;depth++;}h+='<div style=\'margin:10px 0!important;padding:10px!important;background:#f5f5f5!important;border:1px solid #ddd!important;border-radius:3px!important;\'><div style=\'color:#06a!important;font:bold 14px monospace!important;margin-bottom:5px!important;\'>&lt;'+tag+identifier+'&gt; <span style=\'color:#777!important;font-weight:normal!important;font-size:12px!important;\'>(#'+(i+1)+', Depth: '+depth+')</span></div><div style=\'color:#666!important;font:12px monospace!important;margin-bottom:5px!important;\'>'+domPath.join(' > ')+'</div><pre style=\'margin:0!important;padding:8px!important;background:#fff!important;color:#333!important;font:13px monospace!important;overflow:auto!important;white-space:pre-wrap!important;border:1px solid #eee!important;\'>'+el.getAttribute('style').replace(/</g,'&lt;').replace(/>/g,'&gt;')+'</pre></div>';}}h+='<div id=\'inline-styles-close-btn\' style=\'position:absolute!important;top:10px!important;right:10px!important;background:#f33!important;color:#fff!important;border:none!important;padding:5px 10px!important;border-radius:3px!important;cursor:pointer!important;\'>Close</div>';c.innerHTML=h;d.body.appendChild(c);document.getElementById('inline-styles-close-btn').addEventListener('click',function(){c.remove();});})();">Inline Style Inspector</a></p>
<p><img src="/images/bookmarklets/inline-styles.png" alt="a screenshot showing results of this bookmarklet" loading="lazy" decoding="async"></p>
<h4 id="why-this-bookmarklet-is-useful" tabindex="-1">Why This Bookmarklet is Useful</h4>
<p>This inline styles inspector aids in code audits to identify styles for external stylesheets, debugging layout issues, performance optimization through consolidating redundant styles, and checking for styles that might override accessibility features.</p>
<h2 id="third-party-resource-detector" tabindex="-1">Third-Party Resource Detector</h2>
<p>This bookmarklet identifies and lists all external CSS and JavaScript files loaded from domains other than the current one.</p>
<p><a href="javascript:(function(){var d=document;var currentHost=window.location.hostname;function extractDomain(url){try{return new URL(url).hostname;}catch(e){return url;}}function getBaseDomain(domain){var parts=domain.split('.');if(parts.length<=2)return domain;var baseDomain=parts.slice(parts.length-2).join('.');return baseSiteDomain;}var baseSiteDomain=getBaseDomain(currentHost);var externalResources=[];var links=d.getElementsByTagName('link');var scripts=d.getElementsByTagName('script');for(var i=0;i<links.length;i++){if(links[i].href){var linkDomain=extractDomain(links[i].href);if(getBaseDomain(linkDomain)!==baseSiteDomain){var type=links[i].rel==='stylesheet'?'CSS':(links[i].rel||'Link');externalResources.push({type:type,url:links[i].href});}}}for(var j=0;j<scripts.length;j++){if(scripts[j].src){var scriptDomain=extractDomain(scripts[j].src);if(getBaseDomain(scriptDomain)!==baseSiteDomain){externalResources.push({type:'JS',url:scripts[j].src});}}}var c=d.createElement('div');c.style.cssText='position:fixed!important;top:0!important;left:0!important;right:0!important;z-index:9999!important;background:#fff!important;color:#000!important;padding:15px!important;border-bottom:2px solid #000!important;max-height:80vh!important;overflow:auto!important;font:14px Arial!important;box-shadow:0 2px 10px rgba(0,0,0,0.3)!important;';var html='<h3 style=\'margin:0 0 15px!important;font:bold 18px Arial!important;color:#000!important;\'>External Resources</h3>';if(externalResources.length===0){html+='<div style=\'padding:10px!important;background:#f5f5f5!important;color:#000!important;border-left:3px solid #f33!important;\'>No external resources found.</div>';}else{html+='<div style=\'margin-bottom:10px!important;color:#000!important;\'>Found <strong>'+externalResources.length+'</strong> truly external resources:</div>';externalResources.forEach(function(resource,index){var color=resource.type==='CSS'?'#06a':(resource.type==='JS'?'#850':'#444');html+='<div style=\'margin:10px 0!important;padding:10px!important;background:#f5f5f5!important;border:1px solid #ddd!important;border-radius:3px!important;\'><div style=\'color:'+color+'!important;font:bold 14px monospace!important;margin-bottom:5px!important;\'>'+resource.type+' #'+(index+1)+'</div><pre style=\'margin:0!important;padding:8px!important;background:#fff!important;color:#333!important;font:13px monospace!important;overflow:auto!important;white-space:pre-wrap!important;border:1px solid #eee!important;word-break:break-all!important;\'>'+resource.url+'</pre></div>';});}html+='<div id=\'external-resources-close-btn\' style=\'position:absolute!important;top:10px!important;right:10px!important;background:#f33!important;color:#fff!important;border:none!important;padding:5px 10px!important;border-radius:3px!important;cursor:pointer!important;\'>Close</div>';c.innerHTML=html;d.body.appendChild(c);document.getElementById('external-resources-close-btn').addEventListener('click',function(){c.remove();});})();">External Resources Detector</a></p>
<p><img src="/images/bookmarklets/3rd-party.png" alt="a screenshot showing results of this bookmarklet" loading="lazy" decoding="async"></p>
<h3 id="why-this-bookmarklet-is-useful-1" tabindex="-1">Why This Bookmarklet is Useful</h3>
<p>This external resource detector supports security auditing of third-party scripts, performance optimization, GDPR/privacy compliance checks, dependency management, Content Security Policy development, and assessment of offline capabilities by identifying external resources.</p>
<h2 id="component-checker" tabindex="-1">Component Checker</h2>
<p>This bookmarklet helps identify which elements use your design system classes. Elements with your design system prefix are highlighted in green, while all others are outlined in red.</p>
<p><a href="javascript:(function(){const prefix=prompt('Enter CSS class prefix:','vf-');if(prefix===null||prefix===''){return;}const elementsWithPrefix=document.querySelectorAll('*[class*=\''+prefix+'\']');const allElements=document.querySelectorAll('*');elementsWithPrefix.forEach(el=>{el.style.outline='2px solid green';el.style.position='relative';});allElements.forEach(el=>{if(![...el.classList].some(cls=>cls.startsWith(prefix))){el.style.outline='4px solid red';el.style.position='relative';}});})();">Component Checker</a></p>
<p><img src="/images/bookmarklets/component-checker.jpeg" alt="a screenshot showing results of this bookmarklet" loading="lazy" decoding="async"></p>
<h3 id="why-this-bookmarklet-is-useful-2" tabindex="-1">Why This Bookmarklet is Useful</h3>
<p>This component checker assists with design system compliance verification, legacy code detection, visual auditing of component adoption, refactoring planning, quality assurance of developer practices, and creating visual documentation of component usage patterns.</p>
<h3 id="customizing-the-component-checker" tabindex="-1">Customizing the Component Checker</h3>
<p>To adapt this bookmarklet for your own design system, simply modify the namespace value at the beginning of the code. Replace <code>vf-</code> with your own design system's class prefix.</p>
<h2 id="bonus---ass-morphism" tabindex="-1">Bonus - Ass Morphism</h2>
<p>A little fun bookmarklet that makes a dig at the new Liquid Glass or Glassmorphism design and will simply change where it used on a page with a little humour.</p>
<p><a href="javascript:(function() { document.body.innerHTML = document.body.innerHTML.replace(/glassmorphism/gi, 'assmorphism').replace(/liquid glass/gi, 'liquid ass'); })();">Ass Morphism</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Styling The gap with CSS</title>
      <link href="https://www.alwaystwisted.com/articles/styling-the-gap-with-css.html"/>
      <updated>2025-10-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/styling-the-gap-with-css.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in 2017, while working at Monotype on their Design System, I was tasked with coding a new design for a set of logos. This design featured either a vertical line separator at larger viewports or a horizontal one at smaller screens, with the logos stacking as needed. Eager to implement the latest technology,
I opted for CSS Grid. However, the challenge was that, at the time, there was no straightforward way to add a graphical rule to the component without resorting to pseudo-elements and &quot;magic numbers&quot; to achieve a 1px wide line evenly spaced in the grid's margin.</p>
<p>Fast forward to 2025, and we’re on the brink of using new CSS features to create those horizontal or vertical rules (but with bells on).</p>
<p>In June, Patrick and Sam from Microsoft updated us on the Chrome blog about a ~<a href="https://blogs.windows.com/msedgedev/2025/03/19/minding-the-gaps-a-new-way-to-draw-separators-in-css/">previous announcement</a>~ regarding the ability to add ~<a href="https://developer.chrome.com/blog/gap-decorations#the_solution_css_gap_decorations">decorations to the gaps in our flex and grid layouts</a>~. Excited by this news, I spent a couple of hours tinkering in Chrome (Canary) to explore the new rules and their potential use cases. And here we are!</p>
<h2 id="css-gap-decorations" tabindex="-1">CSS Gap Decorations</h2>
<p>As I mentioned, before now (browser support not withstanding) we had to be intuitive if we came across a design that needed vertical or horizontal lines (or both) as part of a layout.
We could opt for using pseudo elements (⁠<code>::before</code>or <code>⁠::after</code>) or we could add additonal DOM elements but these could hit upon other issues. The workarounds could be unitiuitive, we could be adding more CSS that could break if layouts change, additional columns or rows are added. Adding additional DOM elements could work but we could hit upon accessibility issues.
This new specification clears these potential issues up rather neartly as they have no impact on the layouts they’re being applied to as they’re purely visual, they allow for pattern creation as they make use of ⁠<code>repeat()</code> and we don’t need extra markup, we can apply this CSS to what we have already.</p>
<h2 id="new-specification%2C-new-rules%2C-new-properties" tabindex="-1">New Specification, New Rules, New Properties</h2>
<p>The new gap decoration specification introduces familiar syntax, similar to how we write border properties in CSS. It brings two main sets of properties: one for column rules and one for row rules, each with their own width, style, and colour properties.</p>
<h3 id="individual-properties" tabindex="-1">Individual Properties</h3>
<p>For complete control, you can use individual properties:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Column decorations */</span>
<span class="token property">column-rule-width</span><span class="token punctuation">:</span> 2px<span class="token punctuation">;</span>
<span class="token property">column-rule-style</span><span class="token punctuation">:</span> solid<span class="token punctuation">;</span>
<span class="token property">column-rule-color</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>

<span class="token comment">/* Row decorations */</span>
<span class="token property">row-rule-width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
<span class="token property">row-rule-style</span><span class="token punctuation">:</span> solid<span class="token punctuation">;</span>
<span class="token property">row-rule-color</span><span class="token punctuation">:</span> #c0ffee<span class="token punctuation">;</span></code></pre>
<h3 id="shorthand-syntax" tabindex="-1">Shorthand Syntax</h3>
<p>Just like with borders, you can combine these properties using shorthand:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Combined column properties */</span>
<span class="token property">column-rule</span><span class="token punctuation">:</span> 2px solid #bada55<span class="token punctuation">;</span>

<span class="token comment">/* Combined row properties */</span>
<span class="token property">row-rule</span><span class="token punctuation">:</span> 1px solid #c0ffee<span class="token punctuation">;</span></code></pre>
<h3 id="universal-rule" tabindex="-1">Universal Rule</h3>
<p>If you want the same decoration style for both rows and columns, there's a new universal shorthand:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Applied to both row and column gaps */</span>
<span class="token property">rule</span><span class="token punctuation">:</span> 2px solid #bada55<span class="token punctuation">;</span></code></pre>
<p>This new specification brings consistency to how we style gaps in our layouts, whether they're grid, flexbox, or multi-column. The syntax should hopefully feel familiar to anyone who's worked with borders, making it intuitive to implement while offering powerful new styling capabilities.</p>
<h3 id="specialised-properties" tabindex="-1">Specialised Properties</h3>
<p>The specification introduces some powerful properties that give us fine-grained control over how our gap decorations appear and interact. Let’s take a look at these in detail:</p>
<h4 id="rule-break" tabindex="-1">Rule Break</h4>
<p>The <code>rule-break</code> property controls how our gap decorations behave when they meet at intersections or spannign items:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Column decorations */</span>
<span class="token property">column-rule-break</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span> <span class="token comment">/* Lines continue through intersections */</span>
<span class="token property">column-rule-break</span><span class="token punctuation">:</span> intersection<span class="token punctuation">;</span> <span class="token comment">/* Lines stop at intersections */</span>
<span class="token property">column-rule-break</span><span class="token punctuation">:</span> spanning-item<span class="token punctuation">;</span> <span class="token comment">/* Lines break at spanning items */</span>

<span class="token comment">/* Row decorations */</span>
<span class="token property">row-rule-break</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token property">row-rule-break</span><span class="token punctuation">:</span> intersection<span class="token punctuation">;</span>
<span class="token property">row-rule-break</span><span class="token punctuation">:</span> spanning-item<span class="token punctuation">;</span>

<span class="token comment">/* Shorthand for both */</span>
<span class="token property">rule-break</span><span class="token punctuation">:</span> intersection<span class="token punctuation">;</span></code></pre>
<p>This property is particularly useful when you need precise control over how your decorations interact with the layout. For example, in a calendar interface, you might want vertical lines to break at day headers that span multiple columns.</p>
<h4 id="rule-outset" tabindex="-1">Rule Outset</h4>
<p>The <code>⁠rule-outset</code> properties give us precise control over where decorations start and end relative to intersections:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Controls how far decorations extend from their central position */</span>
<span class="token property">column-rule-outset</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span> <span class="token comment">/* Default - meets in the middle */</span>
<span class="token property">column-rule-outset</span><span class="token punctuation">:</span> 0px<span class="token punctuation">;</span> <span class="token comment">/* Aligns with edges */</span>
<span class="token property">column-rule-outset</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span> <span class="token comment">/* Extends beyond edges */</span>
<span class="token property">column-rule-outset</span><span class="token punctuation">:</span> -5px<span class="token punctuation">;</span> <span class="token comment">/* Pulls back from edges */</span>

<span class="token comment">/* Same options for rows */</span>
<span class="token property">row-rule-outset</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>

<span class="token comment">/* Shorthand for both */</span>
<span class="token property">rule-outset</span><span class="token punctuation">:</span> 5px<span class="token punctuation">;</span></code></pre>
<p>The percentage values are relative to the gap width, which means they'll scale proportionally as your layout changes. This is particularly useful for responsive designs where gap sizes might vary.</p>
<h4 id="paint-order" tabindex="-1">Paint Order</h4>
<p>Finally, ⁠<code>rule-paint-order</code> lets us control which decorations appear on top when row and column rules intersect:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Row decorations appear on top of column decorations */</span>
<span class="token property">rule-paint-order</span><span class="token punctuation">:</span> row-over-column<span class="token punctuation">;</span>

<span class="token comment">/* Column decorations appear on top of row decorations */</span>
<span class="token property">rule-paint-order</span><span class="token punctuation">:</span> column-over-row<span class="token punctuation">;</span></code></pre>
<p>This property becomes especially important when working with different rule widths or styles. For example, if you're creating a notebook-style layout with thin vertical lines and thicker horizontal lines, you might want to ensure the horizontal lines appear on top for a more authentic look:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.notebook</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>

  <span class="token property">column-rule</span><span class="token punctuation">:</span> 1px solid #ddd<span class="token punctuation">;</span>
  <span class="token property">row-rule</span><span class="token punctuation">:</span> 2px solid #000<span class="token punctuation">;</span>
  <span class="token property">rule-paint-order</span><span class="token punctuation">:</span> row-over-column<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="pattern-creation-with-%E2%81%A0repeat()" tabindex="-1">Pattern Creation with ⁠<code>repeat()</code></h3>
<p>Just like CSS Grid's ⁠<code>repeat() </code>function, gap decorations can use similar syntax to create patterns. This gives us powerful ways to style our gaps without writing repetitive CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* Simple repetition of the same style */</span>
<span class="token property">row-rule</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>solid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Every row gap has a solid line */</span>

<span class="token comment">/* Alternating styles */</span>
<span class="token property">column-rule-style</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>
  solid dotted
<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Alternates between solid and dotted lines */</span>

<span class="token comment">/* Complex patterns */</span>
<span class="token property">row-rule</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 1px solid black<span class="token punctuation">)</span> 3px solid red<span class="token punctuation">;</span> <span class="token comment">/* Two thin black lines, then one thick red line */</span>

<span class="token comment">/* Multiple properties can use repeat */</span>
<span class="token property">column-rule-width</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>1px 2px<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Alternating thin and thick lines */</span>
<span class="token property">column-rule-color</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>#bada55 #c0ffee<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Alternating colours */</span></code></pre>
<p>These properties give us incredible flexibility... want your decorations to meet perfectly in the middle? Use the default 50%. Need them to stop right at the edges? Set it to 0. Want them to extend a bit further or pull back? Use positive or negative values accordingly.</p>
<h2 id="in-practice" tabindex="-1">In Practice</h2>
<p>Let’s go back to that brand logo component I needed to create in 2017. There were 5 logos that needed to go from being stacked on a narrow viewport to evenly place when the viewport was large enough.
The HTML would look something like this:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo-a.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a logo of brand A<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo-b.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a logo of brand B<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo-c.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a logo of brand C<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo-d.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a logo of brand D<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo-e.svg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>a logo of brand E<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
<p>The CSS to make sure that the gap decorations are displayed as needed looks like this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">ul</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">justify-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>

  <span class="token property">row-rule-width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
  <span class="token property">row-rule-style</span><span class="token punctuation">:</span> solid<span class="token punctuation">;</span>
  <span class="token property">row-rule-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>

  <span class="token property">column-rule-width</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
  <span class="token property">column-rule-style</span><span class="token punctuation">:</span> solid<span class="token punctuation">;</span>
  <span class="token property">column-rule-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>

  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width > 600px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>5<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-g-feature">
<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="bNdMBbG" data-pen-title="gap rule swap (full)" data-user="sturobson" data-token="0552bb39286e4a4efe295e0d81fea4c2" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sturobson/pen/bNdMBbG/0552bb39286e4a4efe295e0d81fea4c2">
  gap rule swap (full)</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<p>By default (on narrow screens), our grid has a single column with five rows, showing the horizontal rules between logos. Once the viewport is wider than 600px, it transforms into a five-column grid with a single row, now showing vertical rules between logos instead.</p>
<p>The beauty of using gap decorations here is that we don't need to worry about which rules show when... the browser handles that for us based on the layout. When there's only one column, column rules aren't visible, and when there's only one row, row rules aren't visible.</p>
<p>Since we're using the same width, style, and color for both our row and column rules, we can simplify our CSS even further using the <code>⁠rule</code> shorthand property:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">ul</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">justify-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>

  <span class="token property">rule</span><span class="token punctuation">:</span> 1px solid black<span class="token punctuation">;</span>

  <span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span>width > 600px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>5<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This single line of ⁠<code>rule: 1px solid black</code> replaces our previous six lines of individual properties, making our code more concise while maintaining the same responsive behavior. The browser still handles the visibility of rules based on the layout, we've just made it more efficient to write.</p>
<div class="at-g-feature">
<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="YPwapgM" data-pen-title="gap rule swap (simplified)" data-user="sturobson" data-token="595ae580e4a2b3c3f934ee42e502d580" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sturobson/pen/YPwapgM/595ae580e4a2b3c3f934ee42e502d580">
  gap rule swap (simplified)</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<h2 id="advanced-gap-decorations" tabindex="-1">Advanced Gap Decorations</h2>
<p>Building on the basic gap decorations, we can create more sophisticated visual patterns and layouts. Here are some advanced techniques that leverage the full power of CSS gap decorations:</p>
<h3 id="non-uniform-gap-patterns" tabindex="-1">Non-uniform Gap Patterns</h3>
<p>Instead of applying the same decoration to every gap, we can create rhythmic patterns or highlight specific sections:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.feature-grid</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>

  <span class="token comment">/* Create alternating pattern for column rules */</span>
  <span class="token property">column-rule</span><span class="token punctuation">:</span> 1px solid black<span class="token punctuation">;</span>
  <span class="token property">column-rule-width</span><span class="token punctuation">:</span> 1px 2px<span class="token punctuation">;</span> <span class="token comment">/* Alternates between 1px and 2px */</span>

  <span class="token comment">/* Apply dotted style to every third row */</span>
  <span class="token property">row-rule</span><span class="token punctuation">:</span> 1px solid black<span class="token punctuation">;</span>
  <span class="token property">row-rule-style</span><span class="token punctuation">:</span> solid solid dotted<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="visually-distinct-sections" tabindex="-1">Visually Distinct Sections</h3>
<p>You can create visual hierarchy by applying different gap decorations to specific grid areas:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.dashboard</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template</span><span class="token punctuation">:</span>
    <span class="token string">'header header header'</span> auto
    <span class="token string">'sidebar main main'</span> 1fr
    <span class="token string">'footer footer footer'</span> auto / 1fr 1fr 1fr<span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>

  <span class="token comment">/* Base gap style */</span>
  <span class="token property">row-rule</span><span class="token punctuation">:</span> 1px solid #ddd<span class="token punctuation">;</span>
  <span class="token property">column-rule</span><span class="token punctuation">:</span> 1px solid #ddd<span class="token punctuation">;</span>

  <span class="token comment">/* Custom gap between header and content */</span>
  <span class="token property">row-rule-width</span><span class="token punctuation">:</span> 3px 1px<span class="token punctuation">;</span>
  <span class="token property">row-rule-color</span><span class="token punctuation">:</span> #0074d9 #ddd<span class="token punctuation">;</span>

  <span class="token comment">/* No vertical divider between main sections */</span>
  <span class="token property">column-rule-width</span><span class="token punctuation">:</span> 1px 0px 1px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="decorative-gap-elements" tabindex="-1">Decorative Gap Elements</h3>
<p>For truly custom gap decorations, we can position decorative elements in the gap space:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.gallery-grid</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>3<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>

  <span class="token comment">/* Create space for decorations */</span>
  <span class="token property">row-rule-outset</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">column-rule-outset</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>

  <span class="token comment">/* Visible rule styles */</span>
  <span class="token property">row-rule</span><span class="token punctuation">:</span> 1px dashed #0074d9<span class="token punctuation">;</span>
  <span class="token property">column-rule</span><span class="token punctuation">:</span> 1px dashed #0074d9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Add decorative elements at intersections */</span>
<span class="token selector">.gallery-grid .gallery-item</span> <span class="token punctuation">{</span>
  <span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Add corner decorations to create the appearance of decorated gaps */</span>
<span class="token selector">.gallery-grid .gallery-item::after</span> <span class="token punctuation">{</span>
  <span class="token property">content</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token property">position</span><span class="token punctuation">:</span> absolute<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span>
    <span class="token function">radial-gradient</span><span class="token punctuation">(</span>circle at center<span class="token punctuation">,</span> #0074d9 0.25rem<span class="token punctuation">,</span> transparent 0.25rem<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">repeating-linear-gradient</span><span class="token punctuation">(</span>
      45deg<span class="token punctuation">,</span>
      #0074d9 0<span class="token punctuation">,</span>
      #0074d9 2px<span class="token punctuation">,</span>
      transparent 2px<span class="token punctuation">,</span>
      transparent 8px
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
  <span class="token property">bottom</span><span class="token punctuation">:</span> -1.75rem<span class="token punctuation">;</span>
  <span class="token property">right</span><span class="token punctuation">:</span> -1.75rem<span class="token punctuation">;</span>
  <span class="token property">z-index</span><span class="token punctuation">:</span> 2<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Hide decorations on last column (every 3rd item) */</span>
<span class="token selector">.gallery-grid .gallery-item:nth-child(3n)::after</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">/* Hide decorations on last row */</span>
<span class="token selector">.gallery-grid .gallery-item:nth-last-child(-n + 3)::after</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="theme-aware-gap-decorations" tabindex="-1">Theme-Aware Gap Decorations</h3>
<p>Using CSS custom properties, we can make gap decorations respond to theme changes:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--gap-primary-color</span><span class="token punctuation">:</span> #0074d9<span class="token punctuation">;</span>
  <span class="token property">--gap-secondary-color</span><span class="token punctuation">:</span> #ddd<span class="token punctuation">;</span>
  <span class="token property">--gap-width-small</span><span class="token punctuation">:</span> 1px<span class="token punctuation">;</span>
  <span class="token property">--gap-width-large</span><span class="token punctuation">:</span> 3px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.dark-theme</span> <span class="token punctuation">{</span>
  <span class="token property">--gap-primary-color</span><span class="token punctuation">:</span> #61dafb<span class="token punctuation">;</span>
  <span class="token property">--gap-secondary-color</span><span class="token punctuation">:</span> #444<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.content-sections</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> <span class="token function">repeat</span><span class="token punctuation">(</span>2<span class="token punctuation">,</span> 1fr<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">gap</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>

  <span class="token comment">/* Theme-aware gap decorations */</span>
  <span class="token property">column-rule</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--gap-width-small<span class="token punctuation">)</span> solid <span class="token function">var</span><span class="token punctuation">(</span>--gap-secondary-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">row-rule</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--gap-width-large<span class="token punctuation">)</span> dotted <span class="token function">var</span><span class="token punctuation">(</span>--gap-primary-color<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Different outset based on theme */</span>
  <span class="token property">row-rule-outset</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--gap-width-large<span class="token punctuation">)</span> * 2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Here’s a handy CodePen demonstrating the above examples, in action:</p>
<div class="at-g-feature">
<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="raxdjzZ" data-pen-title="CSS gap decoration 'advanced' examples" data-user="sturobson" data-token="b1208e43a1ff0c006cd9ab2fc8ee1313" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/sturobson/pen/raxdjzZ/b1208e43a1ff0c006cd9ab2fc8ee1313">
  CSS gap decoration 'advanced' examples</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<h2 id="browser-support" tabindex="-1">Browser Support</h2>
<p>Lacklustre to say the least. Currently, as I write this, styling gaps only works for Chromium-based browsers. You can see <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1963897">the work the Firefox team are doing on this here</a> and <a href="https://bugs.webkit.org/show_bug.cgi?id=298551">where Webkit is up to here</a>.</p>
<p>However, since this is a purely decorative feature (as the specification name suggests), I think we can confidently use it without worrying about browsers that don't yet support it. Non-supporting browsers will simply display layouts without the gap decorations, which doesn't impact functionality.</p>
<p>And it's 2025, just as we recognised in 2012, websites don't need to look identical in every browser. Embracing the platform's natural progressive enhancement capabilities remains as valid as ever.</p>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>Gap decorations solve a problem I've been wrestling with since 2017, and now we have an elegant, declarative solution. No more pseudo-elements. No more magic numbers. Just straightforward CSS that adapts to your layout.</p>
<p>The familiar border-like syntax makes it approachable, while features like rule-outset and pattern creation give us room to get creative.</p>
<h2 id="update%3A-april-2026" tabindex="-1">Update: April 2026</h2>
<p>Since publishing this article, there's been some interesting discussion in the CSS Working Group about how gap decorations behave in certain edge cases, particularly around the <code>rule-inset: overlap-join</code> value.</p>
<p>The issue centres on what happens when you combine <code>rule-inset: overlap-join</code> with <code>rule-visibility-items: between</code>. As a quick reminder, <code>between</code> means decorations only appear where there are items on both sides of the gap. The <code>overlap-join</code> value is designed to help decoration segments join neatly at intersections.</p>
<p>The problem?</p>
<p>When using <code>between</code>, you can end up with decorations that may protrude at intersections where there's no adjacent segment to join with. Imagine a grid where some cells are missing, the rules would stick out awkwardly rather than stopping flush with the items.</p>
<p>There's <a href="https://github.com/w3c/csswg-drafts/issues/13697">ongoing discussion in the CSSWG</a> about how to handle this. The proposals include trimming unjoined decoration segments so they sit flush with adjacent items, preventing those awkward protrusions. The group is also exploring additional controls for decoration behaviour to give authors more flexibility over how gap decorations render in these edge cases.</p>
<p>I'll revisit this once the discussion settles and either update this article accordingly, or write a fresh article demo'ing only these updates.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Context‑Aware Cornering: How inherit() Can Simplify Border‑Radius for Components</title>
      <link href="https://www.alwaystwisted.com/articles/making-context-aware-corners.html"/>
      <updated>2025-10-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/making-context-aware-corners.html</id>
      <content type="html">
        <![CDATA[
        <p>Whilst I was working on my <a href="https://www.alwaystwisted.com/articles/making-context-aware-components">last article about the new <code>inherit()</code> CSS function</a> I looked at how we could use this to help simplify the border radius of child elements based on what the parent element had. But, I’d completely forgot about it when I started to write that article so, as a ‘bonus’, I thought I’d quickly write it up here.</p>
<h2 id="the-design-problem" tabindex="-1">The Design Problem</h2>
<p>Rounded corners can be a small design detail, but they matter. When you nest elements, like a card with padding containing an inner panel with its own background and then a button inside that, the inner corners can easily look out of whack. The inner corners could appear to too small or too large and fail to look part of a overall consistent design.</p>
<p>Designers want a consistent visual rhythm across any nester layers and site visitors can see this visual consistency as a way to ‘trust’ the site they’re using. Yet, different contexts may change the padding and radius means keeping control of the values to make it visually consistent quite tedious.</p>
<p>The design goal here is pretty simple: nested elements should visually respect the parent border radius (corner) so the UI looks cohesive without the need to add lots of extra design tokens or per-component overrides.</p>
<h2 id="how-teams-work-it-out-now" tabindex="-1">How teams work it out now</h2>
<h3 id="parent-publishes-derived-values" tabindex="-1">Parent publishes derived values</h3>
<p>The parent computes and publishes derived variable, for example <code>⁠--inner-radius</code> and <code>⁠--btn-radius</code>, and children read those with ⁠<code>var()</code>. This is explicit and compatible, but it pushes the responsibility to the parent and increases the amount of design tokens and/or Sass variables / CSS Custom Properties you’ll need to create.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-radius</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--card-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--inner-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--btn-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span> * 0.25<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.btn</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--btn-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="each-layer-computes-locally-from-published-base-variables" tabindex="-1">Each layer computes locally from published base variables</h3>
<p>The parent publishes base variables (⁠<code>—card-radius</code>, <code>⁠--card-padding</code>). Each child computes its own value using <code>⁠var()</code> and <code>⁠calc()</code>. This keeps the parent API smaller but requires each child to know the math.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-radius</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--card-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner</span> <span class="token punctuation">{</span>
  <span class="token property">--inner-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.btn</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span> * 0.25<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="build-time-expansion-using-sass" tabindex="-1">Build-time expansion using Sass</h3>
<p>If you want reliable output that works in all browsers and avoids runtime arithmetic, generate the derived radius at build time and emit explicit CSS variables (or classes) for each variant. Sass is a convenient place to do this: generate card variants from a spacing and radius scale, compute inner and button radii using your chosen rules, and output the variables on the card (or as utility classes).</p>
<h4 id="define-your-base-scales-(spacing-and-radius)" tabindex="-1">Define your base scales (spacing and radius)</h4>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$spacing</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">100</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">,</span>
  <span class="token property">200</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">,</span>
  <span class="token property">300</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">,</span>
  <span class="token property">400</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">,</span>
  <span class="token property">500</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token property"><span class="token variable">$radius</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">sm</span><span class="token punctuation">:</span> 0.375rem<span class="token punctuation">,</span>
  <span class="token property">md</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">,</span>
  <span class="token property">lg</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h4 id="create-a-function-for-the-calculations" tabindex="-1">Create a function for the calculations</h4>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@function</span> <span class="token function">inner-radius</span><span class="token punctuation">(</span><span class="token variable">$outer-radius</span><span class="token punctuation">,</span> <span class="token variable">$pad</span><span class="token punctuation">,</span> <span class="token property"><span class="token variable">$factor</span></span><span class="token punctuation">:</span> 0.5<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$result</span></span><span class="token punctuation">:</span> <span class="token variable">$outer-radius</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token variable">$pad</span> <span class="token operator">*</span> <span class="token variable">$factor</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">@if</span> <span class="token selector"><span class="token variable">$result</span> &lt;= 0 </span><span class="token punctuation">{</span>
    <span class="token keyword">@return</span> 0rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">@return</span> <span class="token variable">$result</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">@function</span> <span class="token function">grandchild-radius</span><span class="token punctuation">(</span><span class="token variable">$parent-radius</span><span class="token punctuation">,</span> <span class="token variable">$pad</span><span class="token punctuation">,</span> <span class="token property"><span class="token variable">$factor</span></span><span class="token punctuation">:</span> 0.25<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$result</span></span><span class="token punctuation">:</span> <span class="token variable">$parent-radius</span> <span class="token operator">-</span> <span class="token punctuation">(</span><span class="token variable">$pad</span> <span class="token operator">*</span> <span class="token variable">$factor</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">@if</span> <span class="token selector"><span class="token variable">$result</span> &lt;= 0 </span><span class="token punctuation">{</span>
    <span class="token keyword">@return</span> 0rem<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">@return</span> <span class="token variable">$result</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="create-a-mixin-that-can-generate-the-variables" tabindex="-1">Create a mixin that can generate the variables</h4>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Generic mixin: create radii for a parent element.</span>
<span class="token comment">// - Creates --parent-radius and --parent-pad (base tokens)</span>
<span class="token comment">// - Creates --inner-radius (derived from parent)</span>
<span class="token comment">// - Creates --grandchild-radius (derived from inner and pad)</span>
<span class="token keyword">@mixin</span> <span class="token function">derived-radii</span><span class="token punctuation">(</span>
  <span class="token variable">$parent-radius</span><span class="token punctuation">,</span>
  <span class="token variable">$parent-pad</span><span class="token punctuation">,</span>
  <span class="token property"><span class="token variable">$inner-factor</span></span><span class="token punctuation">:</span> 0.5<span class="token punctuation">,</span>
  <span class="token property"><span class="token variable">$grandchild-factor</span></span><span class="token punctuation">:</span> 0.25
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// expose base tokens on the element</span>
  <span class="token property">--parent-radius</span><span class="token punctuation">:</span> <span class="token variable">#{$parent-radius}</span><span class="token punctuation">;</span>
  <span class="token property">--parent-pad</span><span class="token punctuation">:</span> <span class="token variable">#{$parent-pad}</span><span class="token punctuation">;</span>

  <span class="token comment">// compute values at build time and create them as CSS variables</span>
  <span class="token property"><span class="token variable">$inner</span></span><span class="token punctuation">:</span> <span class="token function">inner-radius</span><span class="token punctuation">(</span><span class="token variable">$parent-radius</span><span class="token punctuation">,</span> <span class="token variable">$parent-pad</span><span class="token punctuation">,</span> <span class="token variable">$inner-factor</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--inner-radius</span><span class="token punctuation">:</span> <span class="token variable">#{$inner}</span><span class="token punctuation">;</span>

  <span class="token property"><span class="token variable">$grand</span></span><span class="token punctuation">:</span> <span class="token function">grandchild-radius</span><span class="token punctuation">(</span><span class="token variable">$inner</span><span class="token punctuation">,</span> <span class="token variable">$parent-pad</span><span class="token punctuation">,</span> <span class="token variable">$grandchild-factor</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--grandchild-radius</span><span class="token punctuation">:</span> <span class="token variable">#{$grand}</span><span class="token punctuation">;</span>

  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="example-using-a-card-with-a-child-(card__inner)-and-grandchild-(.btn)" tabindex="-1">Example using a card with a child (<code>card__inner</code>) and grandchild (<code>.btn</code>)</h4>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.card </span><span class="token punctuation">{</span>
  <span class="token property">--parent-radius</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
  <span class="token property">--parent-pad</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* apply mixin for one variant */</span>
<span class="token selector">.card--lg-400 </span><span class="token punctuation">{</span>
  <span class="token keyword">@include</span> <span class="token function">derived-radii</span><span class="token punctuation">(</span><span class="token function">map-get</span><span class="token punctuation">(</span><span class="token variable">$radius</span><span class="token punctuation">,</span> lg<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">map-get</span><span class="token punctuation">(</span><span class="token variable">$spacing</span><span class="token punctuation">,</span> 400<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner </span><span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">,</span> 0.5rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> <span class="token operator">*</span> 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner .btn </span><span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--grandchild-radius<span class="token punctuation">,</span> 0.375rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="generated-css" tabindex="-1">Generated CSS</h4>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--parent-radius</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
  <span class="token property">--parent-pad</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card--lg-400</span> <span class="token punctuation">{</span>
  <span class="token property">--parent-radius</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--parent-pad</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--inner-radius</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--grandchild-radius</span><span class="token punctuation">:</span> 0.75rem<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">,</span> 0.5rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--parent-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__inner .btn</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--grandchild-radius<span class="token punctuation">,</span> 0.375rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="what-inherit()-is-(recap)" tabindex="-1">What inherit() is (recap)</h2>
<p>As mentioned in the previous article, <code>⁠inherit()</code> is a working draft CSS Values Level 5 function that will substitute the parent element's computed custom-property</p>
<pre class="language-css"><code class="language-css"><span class="token function">inherit</span><span class="token punctuation">(</span>--foo<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span></code></pre>
<p>It returns the parent’s computed value for ⁠<code>--foo</code>. If the immediate parent does not set it, it comes from the nearest ancestor. The second argument is an optional fallback used when the inherited value is invalid.
Using <code>inherit()</code> lets the component say &quot;trust my parent to decide, I'll work it out from there.”. Using <code>var()</code> says &quot;I want this specific token.&quot;</p>
<h2 id="making-context-aware-corners-with-inherit()" tabindex="-1">Making Context-Aware Corners with inherit()</h2>
<p>With ⁠<code>inherit()</code> each component can perform the math locally, reading exactly what the parent resolved. The child expresses how it wants to be inset relative to its parent. Let’s take a card as an example, which has an inner panel and a button.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card__inner<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>btn<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Action<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-radius</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--card-padding</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>

  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* inner computes its radius directly from the parent's computed values */</span>
<span class="token selector">.card__inner</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">inherit</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">,</span> 1.5rem<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">/* button computes its radius from the inner's computed result and the card pad */</span>
<span class="token selector">.btn</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">inherit</span><span class="token punctuation">(</span>--card-radius<span class="token punctuation">,</span> 1.5rem<span class="token punctuation">)</span> -
      <span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--card-padding<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * <span class="token punctuation">(</span>0.5 + 0.25<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">padding</span><span class="token punctuation">:</span> 0.5rem 1rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><code>inherit(--card-radius)</code> reads the parent element’s computed <code>--card-radius</code>. If the parent computes a local alias (for example <code>—card-pad: calc(var(--gap) * 0.75)</code>), <code>inherit()</code> returns that computed result rather than performing a raw token lookup. All <code>inherit()</code> calls in the examples include fallbacks so styles remain predictable when a token is missing or when the feature is not supported.
Here's that example in action:</p>
<div class="at-g-feature">
<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="jErYRzQ" data-pen-title="Untitled" data-user="sturobson" data-token="39baf61023110300790c4e63a73bc3e8" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
      <span>See the Pen <a href="https://codepen.io/sturobson/pen/jErYRzQ/39baf61023110300790c4e63a73bc3e8">
  Untitled</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
      </p>
      <script async src="https://public.codepenassets.com/embed/index.js"></script>
</div>
<h2 id="bonus%2C-grandchildren-and-cleaner-code." tabindex="-1">Bonus, grandchildren and cleaner code.</h2>
<p>For many components it’s cleaner for the inner element to compute and publish a single derived value and for grandchildren to consume that value. The inner computes <code>--inner-radius</code> using <code>inherit()</code> and a local <code>calc()</code>, then publishes it; grandchildren read that value to compute their own corners. This keeps the math in one place and makes intent explicit.</p>
<p>To keep values safe, include sensible fallbacks in your <code>inherit()</code> calls (for example <code>inherit(--outer-pad, 1rem)</code>) and publish reasonable defaults at the parent level so children receive predictable inputs. When appropriate, use <code>clamp()</code> to constrain results; alternatively generate safe derived values at build time (Sass) or have the parent publish an explicit <code>--inner-radius</code> when a guaranteed non‑negative value is required. These approaches avoid duplicated math while keeping runtime behaviour predictable.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.outer</span> <span class="token punctuation">{</span>
  <span class="token property">--outer-radius</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--outer-pad</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--outer-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--outer-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.inner</span> <span class="token punctuation">{</span>
  <span class="token property">--inner-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">inherit</span><span class="token punctuation">(</span>--outer-radius<span class="token punctuation">,</span> 1.5rem<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--outer-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--outer-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.btn</span> <span class="token punctuation">{</span>
  <span class="token property">border-radius</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span>
    <span class="token function">inherit</span><span class="token punctuation">(</span>--inner-radius<span class="token punctuation">,</span> 0.75rem<span class="token punctuation">)</span> - <span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--outer-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.25<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="why-this-may-be-better" tabindex="-1">Why this may be better</h3>
<p>Using ⁠<code>inherit()</code> here shifts ownership: parents publish base variables (radius, padding) and components declare how they want to derive values from their parent. That reduces variable surface area and avoids pushing many derived values onto the parent. It also makes components resilient to parent-side transforms, if the parent computes an alias or applies clamp/scale, children using ⁠<code>inherit()</code> follow the computed result.</p>
<p>Components also become resilient to parent-side transforms. If a parent computes an alias or applies clamp or scaling, children using ⁠inherit() automatically follow the parent’s computed value. The result is cleaner, more self-documenting component CSS: the relationship (calculate from parent) is explicit in the component, and derived definitions are not scattered across the codebase.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Making Context-Aware Components: How CSS inherit() Could Simplify Design Systems</title>
      <link href="https://www.alwaystwisted.com/articles/making-context-aware-components.html"/>
      <updated>2025-10-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/making-context-aware-components.html</id>
      <content type="html">
        <![CDATA[
        <p>Spotted on social media an ‘intent to ship’ post from the Blink team for a new <code>inherit()</code> CSS function. A quick read of what is within <a href="https://chromestatus.com/feature/5996914579472384?gate=4828748570558464">the Chrome Platform Status post</a>, and what was in <a href="https://drafts.csswg.org/css-values-5/#inherit-notation">the W3C specification</a> had my mind buzzing on how this can help us to build better, more ‘context aware’ components for our Design Systems moving forward.</p>
<p>So, with some coffee and the ideas popping I thought I’d write a short post on the <a href="https://www.google.com/url?sa=t&amp;source=web&amp;rct=j&amp;opi=89978449&amp;url=https://www.imdb.com/title/tt1131921/&amp;ved=2ahUKEwjQpdGOzqiQAxVYU0EAHZg7DJAQFnoECBkQAQ&amp;usg=AOvVaw3TRGBRY4RaO1GnnR54nKPf">Johnny Ball</a> of it all.</p>
<p>CSS custom properties already let developers expose and use values from a Design System (often surfaced as design tokens). A child element can read a value set on an ancestor simply by referencing the same custom property via the cascade, but that isn’t a direct way to reference the parent’s computed custom property for in‑place derivation. The new <code>inherit()</code> function looks to help fill that gap. It will explicitly take the parent element’s computed custom‑property value so the child can derive a related value (for example, scale, offset, or colour mix) relative to the parent without duplicating tokens or relying on extra overrides.</p>
<p><code>inherit()</code> is a <a href="https://drafts.csswg.org/css-values-5/">CSS Values Level 5</a> feature that reads a parent’s computed custom property (with an optional fallback, e.g. <code>inherit(--foo, 16px)</code>). It returns the parent’s resolved value, and if the immediate parent doesn’t set one, the value comes from the nearest ancestor that does.</p>
<p>This parent-focused behaviour could be exactly what design systems need: components can derive spacing, density, colour and motion from their container, so you avoid duplicating tokens and get a predictable, context-aware user interface.</p>
<h2 id="but%2C-why-not-make-more-custom-properties%3F" tabindex="-1">But, why not make more custom properties?</h2>
<p>It’s tempting to create Design Tokens for everything you think you’d ever need and add bespoke custom properties everywhere, but inherit() could give us a cleaner alternative. Rather than proliferating tokens, derive local values from a small set of region-level properties so components can stay simple and predictable.</p>
<ul>
<li>A single source of truth: Region or page tokens (spacing, density, accent, motion) stay authoritative; components derive what they need instead of duplicating tokens.</li>
<li>Context‑aware defaults: Components can adapt to their container (compact toolbar vs spacious area), padding, size and spacing update with no extra classes or JS.</li>
<li>Fewer overrides: Set one token on a wrapper and everything inside can adapt with it, avoiding many special-case rules or variants.</li>
</ul>
<h2 id="a-practical-example%2C-making-%E2%80%9Cthe-card%E2%80%9D%3A-from-custom-properties-to-inherit()" tabindex="-1">A practical example, making “the card”: from custom properties to <code>inherit()</code></h2>
<p>Let’s look at a focused example where we can replace a multitude of bespoke custom properties with the new <code>inherit()</code> function.</p>
<p>First, let’s take a simple card component:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>article</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>card__content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">></span></span>A Card Title<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">></span></span>
      Lorem ipsum, dolor sit amet consectetur adipisicing elit. Unde tempore
      veritatis illum voluptas.
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Click here<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>article</span><span class="token punctuation">></span></span></code></pre>
<p>And traditionally (however, more common recently) we would make use of existing custom properties in our code (perhaps from Design Tokens), something like:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing-200</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-400</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-600</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="custom-properties-everywhere" tabindex="-1">Custom Properties Everywhere</h3>
<p>The first version of our card will set every spacing value explicitly with a custom property.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--card-gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-200<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--card-heading-gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content > * + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content h2 + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-heading-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="one-custom-property-to-rule-all-spacing" tabindex="-1">One Custom Property to rule all spacing</h3>
<p>We could tidy this up and reduce the duplication of custom properties inside the card by using some maths. The relationships are now explicit but also local.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">max-width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #000<span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content > * + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content h2 + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="or-we-could-start-using-inherit()" tabindex="-1">Or we could start using <code>inherit()</code></h4>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-spacing</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">max-width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #000<span class="token punctuation">;</span>
  <span class="token property">background</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content > * + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content h2 + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--card-spacing<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can swap <code>var()</code> for <code>inherit()</code> here, but doing so on the card itself is redundant unless the parent provides a token.</p>
<h3 id="inheriting-from-the-parent" tabindex="-1">Inheriting from the parent</h3>
<p>Where this could truly be revolutionary on how we author CSS in component libraries and Design Systems is when can make use of an element’s parent custom properties. Say we have a generic <a href="http://containerist.org/">container</a> regions that has three padding options.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing-200</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-400</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-600</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.region--compact</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-200<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.region--default</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.region--comfortable</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-600<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>With <code>inherit()</code> we can make use of the <code>--gap</code> custom property so that our cards match the look and feel of the parent container.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token comment">/* this will inherit from the parent --gap value */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content > * + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content h2 + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The container region sets the <code>--gap</code>, the card makes use of it with <code>inherit()</code>, cards inside <code>.region--compact</code> become tighter, those in <code>.region--comfortable</code> become more spacious <strong>automatically</strong>. There are no ‘per card’ overrides like <code>.card--compact</code> or <code>.card--comfortable</code> required.</p>
<p>We could, although I think it would make things more complex, also mix all options together. Making use of <code>inherit()</code> for context-aware design decisions and local component specific custom properties.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing-200</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-400</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-600</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.region--compact</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-200<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.region--default</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.region--comfortable</span> <span class="token punctuation">{</span>
  <span class="token property">--gap</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-600<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token property">--card-pad</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--card-gap</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span> * 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--card-heading-gap</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-pad<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content > * + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.card__content h2 + *</span> <span class="token punctuation">{</span>
  <span class="token property">margin-top</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-heading-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="choices-and-fallbacks" tabindex="-1">Choices and Fallbacks</h3>
<p>When you adopt <code>⁠inherit()</code> treat CSS custom properties as the runtime surface your components read from — not the canonical design-token source. Keep the runtime surface small: expose a few region-level properties that express layout and theme intent, and let components derive their implementation values from those.</p>
<p>At the region level expose a tight set of properties for values that change by context: <code>—gap</code>, <code>—density</code>, <code>—base-size</code>, <code>—accent</code>. These are the values components should inherit from their container and treat as authoritative for regional behaviour.</p>
<p>Inside components, keep implementation property names scoped and minimal (for example <code>—card-gap</code>, <code>—btn-pad</code>, <code>—chip-accent</code>). Derive those values from the nearest ancestor using ⁠<code>inherit()</code> rather than adding new global properties. Example:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token comment">/* derive a card-scoped value from the region token */</span>
  <span class="token property">--card-gap</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> 16px<span class="token punctuation">)</span> * 0.75<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-gap<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Use consistent units (<code>rem</code> or <code>px</code>) so <code>⁠calc()</code> is predictable, and include sensible fallbacks in <code>⁠inherit()</code> so components work when a region property is missing or in older browsers. Document ownership: list which properties belong on root, which on page/region wrappers, and which are component implementation details. That keeps naming clear and makes it obvious what <code>⁠inherit()</code> will read and what components compute.</p>
<h2 id="dealing-with-non%E2%80%91supporting-browsers" tabindex="-1">Dealing with non‑supporting browsers</h2>
<p><code>inherit()</code> will be a runtime cascade feature and support will vary while browsers implement it. The goal of any front-end developer is to make components that behave well everywhere today while progressively enhancing where CSS features like <code>inherit()</code> become available.</p>
<p>Here’s a couple of ways to approach using <code>inherit()</code></p>
<p>We could use <code>@supports()</code> to detect the lack of <code>inherit()</code> and provide a simple fallback path.</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@supports</span> <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">calc</span><span class="token punctuation">(</span><span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">.card</span> <span class="token punctuation">{</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--fallback-card-pad<span class="token punctuation">,</span> 12px<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>We could provide some defaults first and then place the <code>inherit()</code> rule afterwards</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.card</span> <span class="token punctuation">{</span>
  <span class="token comment">/* baseline for old browsers */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">/* enhanced when inherit() is available (overrides the baseline) */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> <span class="token function">inherit</span><span class="token punctuation">(</span>--gap<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--card-pad<span class="token punctuation">,</span> 1rem<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="where-to-%22%2B1%22-implementation" tabindex="-1">Where to &quot;+1&quot; implementation</h2>
<p>If you want this CSS feature implemented into web browsers you can upvote them here:</p>
<ul>
<li><a href="https://issues.chromium.org/issues/452071846">Chromium</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1994658">Firefox</a></li>
<li>Safari (not available yet)</li>
</ul>
<h2 id="to-end%E2%80%A6" tabindex="-1">To end…</h2>
<p>The new <code>inherit()</code> CSS feature can make your components naturally context-aware. For Design Systems I think it promises the opportunity for fewer design tokens, fewer overrides and simpler CSS-first adaptations to layouts, typography, theming, and motion.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>... and that&#39;s my rank!</title>
      <link href="https://www.alwaystwisted.com/articles/and-thats-my-rank.html"/>
      <updated>2025-10-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/and-thats-my-rank.html</id>
      <content type="html">
        <![CDATA[
        <p>I was quite excited and intrigued last Friday when I spotted <a href="https://bsky.app/profile/jakearchibald.com/post/3m2tfbx3dhc2r">a post from Jake</a> about an <a href="https://bsky.app/profile/firefoxdevtools.bsky.social/post/3m2rmxpk74c2a">experiment Firefox were conducting</a> to garner information about what web developers wanted to see be included in Interop 2026.</p>
<p>A group effort by major browser makers: Apple, Bocoup, Google, Igalia, Microsoft and Mozilla, the <a href="https://wpt.fyi/interop-2025">Interop Project</a> (essentially) attempts to make the web work the same in every browser. Each year these companies agree on a set of web standards (created by organisations like <a href="https://whatwg.org/">WHATWG</a> and <a href="https://www.w3.org/">W3C</a>) to focus on, to test, and to implement in their respective browsers throughout the year.</p>
<p>I like this idea, it doesn’t hide itself away in a meeting room somewhere, it goes out and asks the community, it looks at what’s being written. What existing features are broken or what bugs they have. What can be improved, and what folks would love to see. Historically, for me, finding out about this has been catching a post (or repost) by a developer advocate that I’ve managed to see in my timeline.</p>
<p>This brings me back to <a href="https://bsky.app/profile/jakearchibald.com/post/3m2tfbx3dhc2r">Jakes post</a>. I opened the link and started looking at the list, it was huge, there were lots of things I thought ‘ooh, that’d be nice’ and as I scrolled down the list <a href="https://bsky.app/profile/sturobson.com/post/3m2tfuo3q4s2p">I decided to make and post a ‘Top 10’</a>, and inspired by <a href="https://matthiasott.com/notes/thats-my-rank">Matthias</a> I thought I’d quickly write a post with that list too.</p>
<p>So, here goes web platform lovers!</p>
<ol class="at-l-stack at-g-content" style="--layout-spacing: var(--space-xs);">
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1006" target="_blank"
        rel="noopener noreferrer">CSS <code>margin-trim</code></a>
      <p>Removes the margins of child elements when they meet the edges of the container.
      </p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1103" target="_blank"
        rel="noopener noreferrer">CSS <code>@supports</code> for at-rules, nesting, and other CSS
        syntax</a>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1136" target="_blank"
        rel="noopener noreferrer">CSS <code>text-wrap: pretty</code></a>
      <p>Prioritises better layout over speed when text is broken into multiple lines.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1165" target="_blank"
        rel="noopener noreferrer">CSS <code>contrast-color()</code> function</a>
      <p>Picks a color that has guaranteed contrast against a specified foreground or background color.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1032" target="_blank"
        rel="noopener noreferrer">CSS <code>@container style()</code></a>
      <p>Apply styles based on the values of custom properties of a container.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1043" target="_blank"
        rel="noopener noreferrer">CSS <code>hanging-punctuation</code> property</a>
      <p>Puts punctuation characters outside of the box to align the text with the rest of the document.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1102" target="_blank"
        rel="noopener noreferrer">CSS Gap decorations</a>
      <p><code>column-rule</code> and <code>row-rule</code> display decorative lines between columns and rows of a flex, grid, or multi-column layout.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1028" target="_blank"
        rel="noopener noreferrer">CSS <code>accent-color</code> property</a>
      <p>Sets a color for checkboxes, radio buttons, and other form controls.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1172" target="_blank"
        rel="noopener noreferrer">CSS anchor positioning</a>
      <p>Places an element based on the position of another element.</p>
  </li>
  <li>
    <a href="https://github.com/web-platform-tests/interop/issues/1083" target="_blank"
        rel="noopener noreferrer">Web Share API</a>
      <p>Invokes the device's native sharing mechanism and passes text, links, files, and other content to share targets.</p>
  </li>
</ol>
<p>As of publishing this article, there's still time to <a href="https://interop-rank.jakearchibald.com">sign-in and add your most wanted features</a> ❤️</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Un-Sass&#39;ing My CSS: Compiling Multiple CSS Files into One</title>
      <link href="https://www.alwaystwisted.com/articles/UnSassing-my-CSS-CSS-imports.html"/>
      <updated>2025-09-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/UnSassing-my-CSS-CSS-imports.html</id>
      <content type="html">
        <![CDATA[
        <p>As mentioned in <a href="/articles/UnSassing-my-CSS/">my last article</a>, my current client work sees me at the start of a much larger Design System project where the deliverables will be as close to vanilla HTML, CSS, and JavaScript as possible. This means we’re not using Sass, and for the first time (in a long time) I’m able to explore more of what modern CSS can do (whilst relying on browser support) instead of reaching for Sass as I normally would.</p>
<p>There are lots of things I like and love about Sass, and there’s a lot that can be done (or can soon to be done) using new CSS features. However, one thing that won’t reach CSS, and something that I think we would always need some aspect of 'tooling' for, is to compile various Sass (or CSS) files into one.</p>
<h2 id="why-compile-css%3F" tabindex="-1">Why Compile CSS?</h2>
<p>Compiling multiple CSS files into one brings several benefits. By reducing the number of CSS files, you decrease HTTP requests, which can significantly improve page load times. Additionally, maintaining a single CSS file can simplify your workflow, making it easier to manage styles across different components. Furthermore, a single, minified CSS file can enhance the performance of your website, leading to a better user experience.</p>
<p>While HTTP/2 can support multiple requests efficiently, relying solely on it and multiple imports doesn't eliminate the overhead and complexity of managing numerous files, which can still impact performance and workflow efficiency. Compiling CSS into a single file, I think, remains essential for streamlined management and consistent performance across all browsers and devices.</p>
<h2 id="tackling-css-compilation-without-sass" tabindex="-1">Tackling CSS Compilation Without Sass</h2>
<p>To achieve this without Sass, we can use tools like PostCSS or a custom script to compile our CSS files. Yes, we could write in one CSS file and depending on your project that might work, but for all of my client work it’s been best to have separate files for aspects of the code that get unified into a single CSS file that is served.</p>
<h3 id="method-1%3A-using-postcss" tabindex="-1">Method 1: Using PostCSS</h3>
<p>PostCSS is a versatile tool that transforms CSS with JavaScript plugins. This method leverages the postcss-import plugin to handle CSS imports and bundle multiple files into one. PostCSS offers a straightforward, configurable approach that integrates well with modern frontend build systems. By using PostCSS, you maintain a clean development structure with separate CSS files while automatically generating a single production file, reducing HTTP requests and improving page load performance.</p>
<h4 id="setting-up-postcss-for-compilation" tabindex="-1">Setting Up PostCSS for Compilation</h4>
<p>To compile your CSS files into one using <a href="https://postcss.org/">PostCSS</a>, follow these steps:</p>
<h4 id="step-1%3A-install-postcss-and-required-plugins" tabindex="-1">Step 1: Install PostCSS and Required Plugins</h4>
<p>First, ensure you have PostCSS installed, along with the <a href="https://github.com/postcss/postcss-import">postcss-import</a> plugin:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save-dev postcss postcss-import</code></pre>
<h4 id="step-2%3A-configure-postcss" tabindex="-1">Step 2: Configure PostCSS</h4>
<p>In your PostCSS configuration file (e.g., postcss.config.js), include the postcss-import plugin:</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'postcss-import'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token comment">// other plugins can be added here</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>The <code>postcss-import</code> plugin automatically resolves nested imports, allowing you to have imports inside imported files while still generating a single compiled output file with the correct cascade order.</p>
</div></div>
<h4 id="step-3%3A-organise-your-css-files" tabindex="-1">Step 3: Organise Your CSS Files</h4>
<p>Create a overarching, global CSS file (e.g., main.css) where you will import all your other CSS files:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/* main.css */</span>

<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'tokens.css'</span><span class="token punctuation">;</span></span>
<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'components/button.css'</span><span class="token punctuation">;</span></span>
<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'components/card.css'</span><span class="token punctuation">;</span></span>
<span class="token atrule"><span class="token rule">@import</span> <span class="token string">'layouts/grid.css'</span><span class="token punctuation">;</span></span></code></pre>
<h4 id="step-4%3A-build-your-css" tabindex="-1">Step 4: Build Your CSS</h4>
<p>Run your PostCSS build process to generate a single output file:</p>
<pre class="language-bash"><code class="language-bash">postcss main.css <span class="token parameter variable">-o</span> output.css</code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>PostCSS can seamlessly integrate with popular build tools like webpack, Gulp, and Rollup, allowing you to incorporate CSS compilation into your existing development workflow without potential, additional configuration headaches.</p>
</div></div>
<h3 id="method-2%3A-custom-script-for-compilation" tabindex="-1">Method 2: Custom Script for Compilation</h3>
<p>If you prefer not to use PostCSS, you could instead create a Node.js script to compile your CSS.
This method uses a custom Node.js script to handle CSS compilation without additional dependencies like PostCSS. The script reads your main CSS file, processes any @import statements it finds, concatenates the contents of all imported files, and outputs a single compiled CSS file. This approach gives you complete control over the compilation process and can be tailored to specific project requirements. It's lightweight, requires minimal setup beyond Node.js itself, and can be easily integrated into your existing workflow or build process.</p>
<p><strong>Step 1: Create the Script</strong>
Create a file named compile-css.js and add the following code:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Function to read and compile CSS</span>
<span class="token keyword">function</span> <span class="token function">compileCSS</span><span class="token punctuation">(</span><span class="token parameter">inputFile<span class="token punctuation">,</span> outputFile</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> cssContent <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>inputFile<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> imports <span class="token operator">=</span> cssContent<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">@import\s+['"]([^'"]+)['"]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token keyword">let</span> compiledCSS <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>

  <span class="token comment">// Read and append each imported CSS file</span>
  imports<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">importStatement</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> filePath <span class="token operator">=</span> importStatement<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">['"]([^'"]+)['"]</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> fullPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">dirname</span><span class="token punctuation">(</span>inputFile<span class="token punctuation">)</span><span class="token punctuation">,</span> filePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
    compiledCSS <span class="token operator">+=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>fullPath<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'\n'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Write the compiled CSS to the output file</span>
  fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>outputFile<span class="token punctuation">,</span> compiledCSS<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Compiled CSS written to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>outputFile<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Usage</span>
<span class="token keyword">const</span> inputCSSFile <span class="token operator">=</span> <span class="token string">'index.css'</span><span class="token punctuation">;</span> <span class="token comment">// Your main CSS file</span>
<span class="token keyword">const</span> outputCSSFile <span class="token operator">=</span> <span class="token string">'output.css'</span><span class="token punctuation">;</span> <span class="token comment">// Output file</span>

<span class="token function">compileCSS</span><span class="token punctuation">(</span>inputCSSFile<span class="token punctuation">,</span> outputCSSFile<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>With the flat file structure and single-level import strategy I employ, nested imports (you can do with <code>postcss-import</code> aren't necessary for my project setup, simplifying the compilation process while maintaining clean organisation.</p>
</div></div>
<p><strong>Step 2: Run the Script</strong>
Ensure you have Node.js installed, then run the script from your terminal:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">node</span> compile-css.js</code></pre>
<p>This will read the index.css file, compile all the @imported CSS files, and create a single output.css file.</p>
<h2 id="conclusion" tabindex="-1">Conclusion</h2>
<p>Compiling multiple CSS files into one is a straightforward process, whether you choose to use PostCSS or a custom Node.js script. This approach not only improves the performance of your website but also simplifies the management of your stylesheets. By keeping your styles organised and consolidated, you can focus more on development and less on file management. As you continue to refine your CSS workflow, consider incorporating these methods to enhance your projects.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Un-Sass’ing my CSS</title>
      <link href="https://www.alwaystwisted.com/articles/UnSassing-my-CSS.html"/>
      <updated>2025-08-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/UnSassing-my-CSS.html</id>
      <content type="html">
        <![CDATA[
        <p>If you’ve been following me for a while, you’ll know that I’m a big fan of Sass. Whether it's writing articles, running workshops, curating the Sass News email newsletter, or serving as the tech editor for SitePoint, commissioning two fresh Sass articles each week, it’s safe to say I’ve been an enthusiastic supporter of Sass for the last fourteen years.</p>
<h2 id="however" tabindex="-1">However</h2>
<p>I’m currently assisting a client with what could be the beginning of a brand new Design System through several smaller projects. The website is somewhere between ten to fifteen years old, and the front-end team, while embedded, cannot necessarily keep pace with the advancements in modern CSS. This is largely due to the constraints of the old codebase, which make it challenging to adopt new practices and technologies.</p>
<p>Because of this, we decided to leverage ‘the platform’ as much as possible. We’re not using a preprocessor; instead, we’re relying on features that are ‘newly available’ or ‘widely available’ with Baseline, using modern CSS and almost all the toys in the box.</p>
<p>The only thing we are using is a small script that compiles all the CSS files into one larger file, following the ⁠@import order. This is because, architecturally, we are colocating a component’s CSS file with its corresponding HTML file in the same folder, but not within the same file (yuck!).</p>
<h2 id="un-sass%E2%80%99ing%3F" tabindex="-1">Un-Sass’ing?</h2>
<p>With this in mind, I thought I’d start another little series of articles. This time, I’ll be showcasing how aspects of modern CSS can replace your favourite CSS preprocessor, what I’m goint to call “Un-Sass’ing.”</p>
<h2 id="adding-transparency-to-a-colour" tabindex="-1">Adding Transparency To A Colour</h2>
<p>As we work in an agile environment, not everything is fully developed or finalised yet. One of the requirements we've encountered is the need to create transparent backgrounds. Since we are not using Sass for this project, I wondered if we could achieve similar effects using CSS.</p>
<p>In my search, I <a href="https://bsky.app/profile/sturobson.com/post/3lw5hz5aink2d">discovered the ⁠color() function</a>, and Manuel kindly shared some other <a href="https://codepen.io/matuzo/pen/EaVwEoJ?editors=0100">examples of different ways to implement transparency in using modern CSS</a>.</p>
<h3 id="the-sass-way" tabindex="-1">The Sass Way</h3>
<p>In previous projects using Sass, we could easily add transparency to colours using the <code>⁠rgba()</code> function. This function allows us to define a colour with an alpha value, which determines the level of transparency. For instance, we would typically define a colour variable at the beginning of our stylesheet, like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$primary-color</span></span><span class="token punctuation">:</span> #c0ffee<span class="token punctuation">;</span>
<span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token variable">$primary-color</span><span class="token punctuation">,</span> 0.4<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>By using ⁠<code>rgba()</code>, Sass interprets ⁠<code>$primary-color</code> as a colour value and allows us to specify the alpha channel without needing to break down the colour into its red, green, and blue components manually.
This approach made it straightforward to create semi-transparent backgrounds, hover effects, or overlays, enhancing the visual depth of our designs.</p>
<h3 id="the-css-way" tabindex="-1">The CSS Way</h3>
<p>Now, with modern CSS, we have a variety of options to achieve similar results without relying on a preprocessor. One effective method is using the <code>⁠color()</code> function, which allows us to define a colour based on a CSS variable and adjust its transparency.</p>
<p>According to the ~<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color">MDN Web Docs</a>~, the ⁠<code>color()</code> function enhances our ability to work with colours in CSS, making it easier to create visually appealing designs that adapt to different contexts. This flexibility allows us to maintain a streamlined workflow while achieving the desired effects, such as transparency, without the need for a preprocessor.</p>
<p>For example, we can create a transparent background using the following syntax:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.component</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>from <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span> srgb r g b / 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>In this example, <code>⁠var(--color-primary)</code> retrieves the primary colour defined in CSS variables, while ⁠srgb specifies the colour space. The <code>⁠r g b</code> components extract the red, green, and blue values, and the ⁠<code>/ 0.2</code> at the end sets the alpha channel for transparency, allowing us to effectively control the opacity of the colour.</p>
<h2 id="the-other-css-ways" tabindex="-1">The Other CSS Ways</h2>
<p>In addition to the <code>color()</code> function, modern CSS provides several other methods for adding transparency and manipulating colours using CSS custom properties:</p>
<h3 id="using-rgba()-directly" tabindex="-1">Using <code>rgba()</code> Directly</h3>
<p>You can use the <code>rgba()</code> function directly in CSS to define colours with transparency by referencing a custom property:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.component</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span> 0.4<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="utilising-hsla()" tabindex="-1">Utilising <code>hsla()</code></h3>
<p>The <code>hsla()</code> function allows you to work with colours in the HSL colour space, providing another way to define colours with transparency using custom properties:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">hsl</span><span class="token punctuation">(</span>91<span class="token punctuation">,</span> 52%<span class="token punctuation">,</span> 59%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.component</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">hsla</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span> 0.4<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="mixing-with-%E2%81%A0color-mix()" tabindex="-1">Mixing with <code>⁠color-mix()</code></h3>
<p>The <code>⁠color-mix()</code> function allows you to blend a custom property with another colour, including transparency, to create a new colour effect:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.component</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span> 20%<span class="token punctuation">,</span> transparent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="fin" tabindex="-1">Fin</h2>
<p>I still have some trepidation about fully transitioning to CSS-only solutions. While modern CSS offers a wealth of features that can effectively replace many of the functionalities traditionally provided by Sass, I believe that making decisions on tooling should be based on a project-by-project basis. Each project has its unique requirements, and the choice between using Sass or relying solely on CSS should reflect the specific needs and goals of that project.</p>
<p>Sass still has its benefits, particularly in managing complex styles and maintaining a consistent design system. However, as the demand for modern design solutions increases, it’s evident that there is a growing array of new CSS capabilities that can handle many tasks we previously relied on Sass for.</p>
<p>This article may mark the beginning on &quot;Un-Sass’ing&quot; CSS, where I could continue to showcase how to replace favoured Sass functionality with modern CSS techniques.</p>
<p>Would you like to learn more about what and how we can replace Sass with CSS? <a href="https://bsky.app/profile/sturobson.com">Let me know</a>!</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Creating a Component for Positioning Content</title>
      <link href="https://www.alwaystwisted.com/articles/creating-a-component-for-positiong-content.html"/>
      <updated>2025-07-30T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/creating-a-component-for-positiong-content.html</id>
      <content type="html">
        <![CDATA[
        <p>For a recent client project, I’ve been helping them transform and update parts of their web presence, and one of the key updates was a brand-new home page. With initial designs to work from, I realised that one particular container could serve as a reusable component across various sections of the project.</p>
<p>This component is relatively simple in appearance—a background image with some text overlaid. In the designs I encountered, the text was primarily positioned in the ‘bottom left’ and ‘top center’ of the container. I thought it would be efficient to use ⁠place-self to easily define where the content should sit, allowing for a clean and flexible layout that can adapt to different content needs.</p>
<p>In this post, I’ll walk you through the process of creating this component, showcasing how to implement it using CSS Grid and the ⁠<code>place-self</code> property.</p>
<h3 id="component-overview" tabindex="-1">Component Overview</h3>
<p>Looking at the design I found three things that could be changeable.</p>
<h3 id="flexible-positioning%3A" tabindex="-1">Flexible Positioning:</h3>
<p>Although the current designs only had the text positioned in two places, I thought we should make it more flexible and allow the content area to be in more positions. Using <code>place-self</code> this component can offer nine distinct positioning options.</p>
<h3 id="custom-width%3A" tabindex="-1">Custom Width:</h3>
<p>Another feature I wanted to add was the ability to set a custom width for the content block (with a sensible default). Defining the width using CSS variables allows us to easily adapt the component to fit various design needs.</p>
<h3 id="surface-options%3A" tabindex="-1">Surface Options:</h3>
<p>The choice of background image would determine if the content block is more accessible and readable so I wanted to support two surface styles: light and dark. The light surface features a subtle gray background, providing contrast against darker images, while the dark surface offers a semi-transparent black background for improved visibility on lighter images.</p>
<h2 id="building-the-component-structure" tabindex="-1">Building the component structure</h2>
<p>To effectively position content on a background image, I needed to establish a clear HTML structure for the component. Essentially, I wanted a parent and child element. The parent being the horizontal slice of the web page, a section, and a child component that holds the content but defines their position, width, and colours.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_DS-spot-content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
    <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_DS-spot-content__content<span class="token punctuation">"</span></span>
    <span class="token attr-name">data-surface</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span>
    <span class="token attr-name">data-position</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>start start<span class="token punctuation">"</span></span>
    <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">--spot-content-width</span><span class="token punctuation">:</span> 400px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span></span>
  <span class="token punctuation">></span></span>
    /* Content Goes Here */
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">></span></span></code></pre>
<p>Now we’ve got the basics, let’s get some styling.</p>
<h2 id="styling-the-component" tabindex="-1">Styling the component</h2>
<p>To bring our component to life, we will use CSS Grid for layout management and the place-self property for precise content positioning. This approach allows us to create a flexible and responsive design that adapts seamlessly to various screen sizes.</p>
<h3 id="using-css-grid" tabindex="-1">Using CSS Grid</h3>
<p>CSS Grid is a powerful layout system that enables us to create complex grid-based layouts with ease. For our component, we can define a grid container that takes up the full height of the viewport, allowing us to position our content block anywhere within that space.
Here's how we set up the grid layout:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">._DS-spot-content</span> <span class="token punctuation">{</span>
  <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 100dvh<span class="token punctuation">;</span> <span class="token comment">/* Full viewport height */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
  <span class="token selector">> *</span> <span class="token punctuation">{</span>
    <span class="token property">grid-area</span><span class="token punctuation">:</span> 1 / 1<span class="token punctuation">;</span> <span class="token comment">/* Ensures the content block occupies the full grid area */</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="styling-with-place-self" tabindex="-1">Styling with <code>place-self</code></h4>
<p>The <code>place-self</code> property is a shorthand that combines both <code>align-self </code>and <code>justify-self</code>, allowing us to control the alignment of grid items with a single declaration. This simplifies our CSS and makes it easier to manage the positioning of content blocks.</p>
<h4 id="positioning-logic" tabindex="-1">Positioning Logic</h4>
<p>Using <code>place-self</code>, we can specify how the content block should be aligned within the grid.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">[data-position='start']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> start start<span class="token punctuation">;</span> <span class="token comment">/* Aligns content to the top-left */</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='end']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> end<span class="token punctuation">;</span> <span class="token comment">/* Aligns content to the bottom-right */</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='center']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token comment">/* Centers content both vertically and horizontally */</span>
<span class="token punctuation">}</span>

<span class="token comment">/* Additional positioning configurations */</span>
<span class="token selector">[data-position='start start']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> start start<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='start center']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> start center<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='start end']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> start end<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='center center']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> center center<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='center start']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> center start<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='center end']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> center end<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='end start']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> end start<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='end center']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> end center<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">[data-position='end end']</span> <span class="token punctuation">{</span>
  <span class="token property">place-self</span><span class="token punctuation">:</span> end end<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="defining-the-width-with-a-custom-property" tabindex="-1">Defining the width with a custom property</h3>
<p>One of the features of this component is the ability to define the width of the content block using a custom CSS property. To implement this, we use a CSS custom property, <code>—spot-content-width</code>, which can be set directly as an inline style of the HTML or defined within the CSS itself.</p>
<p>Having the custom property as an inline style could benefit implementation in a CSS, where a content creator can decide how wide this content block should be, like this:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
  <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_DS-spot-content__content<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-surface</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dark<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-position</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>start start<span class="token punctuation">"</span></span>
  <span class="token special-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span><span class="token value css language-css"><span class="token property">--spot-content-width</span><span class="token punctuation">:</span> 400px<span class="token punctuation">;</span></span><span class="token punctuation">"</span></span></span>
<span class="token punctuation">></span></span>
  /* Content Goes Here */
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>We could also set a default in the CSS, if there is no inline CSS custom property:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">._DS-spot-content__content</span> <span class="token punctuation">{</span>
  <span class="token property">max-width</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spot-content-width<span class="token punctuation">,</span> 50%<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Default width set to 50% */</span>
  <span class="token property">padding</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="defining-surface-styles" tabindex="-1">Defining Surface Styles</h3>
<p>As the content block will be on top of an image we need to enhance the readability and accessibility of it by defining a couple of surface/text colour styles.</p>
<p>We will support two distinct surface styles: light and dark. Each style is designed to provide an optimal contrast to the background image.</p>
<h4 id="light" tabindex="-1">Light</h4>
<p>The light option would be used when the background image is overly dark, or dark where the content is positions.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">._DS-spot-content__content[data-surface='light']</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>220<span class="token punctuation">,</span> 220<span class="token punctuation">,</span> 220<span class="token punctuation">,</span> 0.5<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="dark" tabindex="-1">Dark</h4>
<p>The dark styling option would be for the opposite, whe nthe background image is overly bright, or bright where the content is to be positioned.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">._DS-spot-content__content[data-surface='dark']</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">rgba</span><span class="token punctuation">(</span>20<span class="token punctuation">,</span> 20<span class="token punctuation">,</span> 20<span class="token punctuation">,</span> 0.3<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Semi-transparent dark gray */</span>
  <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span> <span class="token comment">/* Text colour for better contrast */</span>
<span class="token punctuation">}</span></code></pre>
<p>In the HTML we set a data attribute <code>data-surface</code>:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span>
  <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_DS-spot-content__content<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-surface</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>light<span class="token punctuation">"</span></span>
  <span class="token attr-name">data-position</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>center center<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span>
  /* Content Goes Here */
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<h2 id="example" tabindex="-1">Example</h2>
<div class="at-g-feature">
<iframe height="500" style="min-height: 300px; width: 100%;" scrolling="no" title="Always Twisted - Spot Content Component " src="https://codepen.io/sturobson/embed/QwjdqZY?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/QwjdqZY">
  Always Twisted - Spot Content Component </a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<p>We explored the process of creating a reusable component for positioning content over a background image. Using CSS Grid and the <code>⁠place-self</code> property, we achieved a flexible layout that allows for precise content placement with multiple positioning options. Additionally, we included a custom width setting and surface styles to enhance readability and adapt the component to various design needs.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 12) - Creating a Penpot Design Tokens Format with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-12.html"/>
      <updated>2025-04-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-12.html</id>
      <content type="html">
        <![CDATA[
        <p>In the last article, I delved into <a href="https://www.alwaystwisted.com/articles/design-tokens-in-penpot">Penpot's new Design Tokens feature</a>, a promising development that (being a very early implementation) had its share of limitations.</p>
<p>Today, in this Design Tokens Workflow tutorial, I am going to walk through creating a build script in Style Dictionary that will generate a Penpot-ready JSON file with all our design tokens.</p>
<p>In Penpot's implementation, design tokens are created and managed through a UI. The tokens can be grouped into &quot;Token Sets&quot; and &quot;Token Themes&quot;, offering a flexible hierarchical structure. You can learn more about Penpot's Design Tokens from their ~<a href="https://help.penpot.app/user-guide/design-tokens/">official documentation</a>~.</p>
<h2 id="creating-token-examples-in-json-format" tabindex="-1">Creating Token Examples in JSON Format</h2>
<p>To illustrate the process of creating Penpot-ready <code>.json</code>, let's use a few (crude) design token examples.</p>
<h3 id="core-tokens" tabindex="-1">Core Tokens</h3>
<p>We start with our core tokens, specifically our colour tokens. These tokens will be stored in a file named ⁠<code>core/01-base/color.tokens</code> to ensure they are imported first by Penpot.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#cce4f6"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#b3d4ee"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffe5e5"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffcccc"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="semantic-tokens" tabindex="-1">Semantic Tokens</h3>
<p>Next, we have our semantic tokens, which will override our base tokens where required. Let's create two files for this, ⁠semantic/01-base/color.tokens.json and ⁠semantic/02-brand-a/color.tokens.json. These files will contain semantic color tokens for our base theme and a specific brand, respectively.</p>
<p>Here's an example for ⁠<code>semantic/01-brand-a/color.tokens</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"muted"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>And for <code>semantic/02-brand-b/color.tokens</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"muted"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="an-importance-for-numbering-folders" tabindex="-1">An Importance for Numbering Folders</h3>
<p>In the above examples, you can see that the folders storing our token files are prefixed with a number (01, 02). This numbering serves a vital purpose: it determines the import order in Penpot.</p>
<p>In Penpot, the order of tokens matters because of the way it implements the cascade (like <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascade/Cascade">the cascade in CSS</a>. A later token can overwrite a previous one if they have the same name. By numbering our folders, we can ensure that our tokens are imported in the correct order, thus preserving our desired cascade.</p>
<p>Furthermore, this numbering system also helps to keep our design token files organised and easy to navigate, especially in larger projects with many token files. The visual hierarchy provided by the numbering can make it easier to understand the relationships and dependencies between different tokens.</p>
<h2 id="a-note-on-penpots-propietary-.json-structure" tabindex="-1">A Note On Penpots Propietary <code>.json</code> Structure</h2>
<p>Before we proceed with configuring Style Dictionary, we should take a look at the proprietary <code>json</code> structure that Penpot uses for its tokens. This structure allows Penpot to manage token sets and themes effectively.
In Penpot, you can group design tokens into distinct sets, apply them across multiple themes, and control their cascading order. The mechanism behind this is a special structure in the JSON file that includes the ⁠<code>$themes</code> array and the ⁠<code>$metadata</code> object.</p>
<pre class="language-json"><code class="language-json"><span class="token property">"$themes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"default"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"default"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand a"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"brand-a"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token property">"$metadata"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"tokenSetOrder"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">"base"</span><span class="token punctuation">,</span>
      <span class="token string">"default"</span><span class="token punctuation">,</span>
      <span class="token string">"brand-a"</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeThemes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">"/default"</span><span class="token punctuation">,</span>
      <span class="token string">"/brand a"</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeSets"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">"base"</span><span class="token punctuation">,</span>
      <span class="token string">"default"</span><span class="token punctuation">,</span>
      <span class="token string">"brand-a"</span>
    <span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
<p>Let's break this structure down:</p>
<ul>
<li><code>$themes</code>: This is an array of theme objects. Each theme object must have a <code>⁠name</code> and a <code>⁠selectedTokenSets</code> object. The ⁠`selectedTokenSets object should list all token sets that are enabled for that theme.</li>
<li>⁠<code>$metadata</code>: This object contains three properties: <code>tokenSetOrder</code>, <code>⁠activeThemes</code>, and <code>⁠activeSets</code>.
<ul>
<li><code>tokenSetOrder</code>: An array that defines the order in which token sets are imported into Penpot. This is vital for controlling the cascade of tokens.</li>
<li>⁠<code>activeThemes</code>: An array that lists the themes currently active in the Penpot interface.</li>
<li>⁠<code>activeSets</code>: An array that indicates the token sets active in the Penpot interface.</li>
</ul>
</li>
</ul>
<p>This structure provides a flexible and powerful way to manage design tokens in Penpot, enabling you to maintain consistency across different themes and platforms so we need to make sure our Style Dictionary build script creates the output similar to this too.</p>
<h2 id="configuring-style-dictionary-for-penpot" tabindex="-1">Configuring Style Dictionary for Penpot</h2>
<p>To turn these design tokens into a format that Penpot can read we need to create a custom format and a helper function in Style Dictionary. Here is the complete code we need. I will break it down further next:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">'fs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> path <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> <span class="token function-variable function">getThemesAndMetadata</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> coreFolders <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/core/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> semanticFolders <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> themes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> tokenSetOrder <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token comment">// Include core folders in the token set order</span>
  <span class="token keyword">const</span> sortedCoreFolders <span class="token operator">=</span> coreFolders<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> aPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> bPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> aPrefix <span class="token operator">-</span> bPrefix<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  sortedCoreFolders<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">folder</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> folderName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>folder<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\d+-</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove numeric prefix</span>
    tokenSetOrder<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>folderName<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Include semantic folders in the token set order and themes</span>
  <span class="token keyword">const</span> sortedSemanticFolders <span class="token operator">=</span> semanticFolders<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> aPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> bPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> aPrefix <span class="token operator">-</span> bPrefix<span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  sortedSemanticFolders<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">folder</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> folderName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>folder<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\d+-</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove numeric prefix</span>
    tokenSetOrder<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>folderName<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>folderName <span class="token operator">!==</span> <span class="token string">'base'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      themes<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> folderName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">-</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token literal-property property">selectedTokenSets</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token string">'enabled'</span><span class="token punctuation">,</span>
          <span class="token punctuation">[</span>folderName<span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'enabled'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    themes<span class="token punctuation">,</span>
    <span class="token literal-property property">metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">$metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">tokenSetOrder</span><span class="token operator">:</span> tokenSetOrder<span class="token punctuation">,</span>
        <span class="token literal-property property">activeThemes</span><span class="token operator">:</span> themes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">theme</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token literal-property property">activeSets</span><span class="token operator">:</span> tokenSetOrder<span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'json/penpot'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token function-variable function">simplifyTokens</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
      Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>tokens<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">[</span>key<span class="token punctuation">,</span> token<span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>$value <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          result<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">$value</span><span class="token operator">:</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">,</span>
            <span class="token literal-property property">$type</span><span class="token operator">:</span> token<span class="token punctuation">.</span>$type<span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> token <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          result<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">simplifyTokens</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> <span class="token punctuation">{</span> themes<span class="token punctuation">,</span> metadata <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">getThemesAndMetadata</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> <span class="token function">simplifyTokens</span><span class="token punctuation">(</span>dictionary<span class="token punctuation">.</span>tokens<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span> <span class="token operator">...</span>semanticTokens<span class="token punctuation">,</span> <span class="token literal-property property">$themes</span><span class="token operator">:</span> themes<span class="token punctuation">,</span> <span class="token operator">...</span>metadata <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token keyword">null</span><span class="token punctuation">,</span>
      <span class="token number">2</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Find all token files matching the pattern</span>
<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary instance</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">json_combined</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'penpot.json'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'json/penpot'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token literal-property property">global</span><span class="token operator">:</span> <span class="token string">'src/tokens/base/**/*.tokens'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">semantic</span><span class="token operator">:</span> <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Ensure the build directory exists</span>
<span class="token keyword">const</span> buildDir <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>buildDir<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>buildDir<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Execute the build process for the json_combined platform</span>
<span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="custom-format" tabindex="-1">Custom Format</h3>
<p>We register a custom format with the ⁠<code>StyleDictionary.registerFormat</code> method. This custom format, named <code>json/penpot</code>, contains an asynchronous ⁠format function that simplifies the tokens. It also uses the <code>⁠getThemesAndMetadata</code> function to generate themes and metadata. The function then combines these into a single Penpot-friendly JSON string.</p>
<pre class="language-javascript"><code class="language-javascript">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'json/penpot'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">format</span><span class="token operator">:</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token function-variable function">simplifyTokens</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">tokens</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
      Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>tokens<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">[</span>key<span class="token punctuation">,</span> token<span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>token<span class="token punctuation">.</span>$value <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          result<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">$value</span><span class="token operator">:</span> token<span class="token punctuation">.</span>$value<span class="token punctuation">,</span>
            <span class="token literal-property property">$type</span><span class="token operator">:</span> token<span class="token punctuation">.</span>$type<span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> token <span class="token operator">===</span> <span class="token string">'object'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          result<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">simplifyTokens</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> <span class="token punctuation">{</span> themes<span class="token punctuation">,</span> metadata <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">getThemesAndMetadata</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> <span class="token function">simplifyTokens</span><span class="token punctuation">(</span>dictionary<span class="token punctuation">.</span>tokens<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>
      <span class="token punctuation">{</span> <span class="token operator">...</span>semanticTokens<span class="token punctuation">,</span> <span class="token literal-property property">$themes</span><span class="token operator">:</span> themes<span class="token punctuation">,</span> <span class="token operator">...</span>metadata <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token keyword">null</span><span class="token punctuation">,</span>
      <span class="token number">2</span>
    <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="helper-function" tabindex="-1">Helper Function</h3>
<p>The <code>⁠getThemesAndMetadata</code> function is a (rather large) helper function that retrieves the sorted list of core and semantic token directories, generates themes for each semantic directory (except 'base'), and sets the order of token sets import for Penpot.</p>
<ol>
<li>Getting the List of Folders
The function begins by retrieving a list of all core and semantic token directories.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> coreFolders <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/core/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> semanticFolders <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<ol start="2">
<li>Initialising the Themes and Token Sets
The <code>⁠themes</code> and ⁠<code>tokenSetOrder</code> arrays are initialised. They will store the themes and the order of token sets for Penpot.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> themes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> tokenSetOrder <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<ol start="3">
<li>Sorting and Processing Core Folders
The core folders are sorted numerically based on their prefixes and added to the ⁠<code>tokenSetOrder</code> array.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sortedCoreFolders <span class="token operator">=</span> coreFolders<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> aPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">[</span><span class="token string">'-'</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> bPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">[</span><span class="token string">'-'</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> aPrefix <span class="token operator">-</span> bPrefix<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

sortedCoreFolders<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">folder</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> folderName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>folder<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\d+-</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove numeric prefix</span>
  tokenSetOrder<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>folderName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<ol start="4">
<li>Sorting and Processing Semantic Folders
The semantic folders are also sorted numerically based on their prefixes. The folder names are added to the ⁠<code>tokenSetOrder</code> array. If a folder name is not 'base', a theme is created for it and added to the <code>⁠themes</code> array.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> sortedSemanticFolders <span class="token operator">=</span> semanticFolders<span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> aPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>a<span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">[</span><span class="token string">'-'</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> bPrefix <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span><span class="token punctuation">.</span>split<span class="token punctuation">[</span><span class="token string">'-'</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> aPrefix <span class="token operator">-</span> bPrefix<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

sortedSemanticFolders<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">folder</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> folderName <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>folder<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\d+-</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove numeric prefix</span>
  tokenSetOrder<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>folderName<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>folderName <span class="token operator">!==</span> <span class="token string">'base'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    themes<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      <span class="token literal-property property">name</span><span class="token operator">:</span> folderName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">-</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token literal-property property">selectedTokenSets</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token string">'enabled'</span><span class="token punctuation">,</span>
        <span class="token punctuation">[</span>folderName<span class="token punctuation">]</span><span class="token operator">:</span> <span class="token string">'enabled'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<ol start="5">
<li>Returning Themes and Metadata
Finally, the function returns an object containing the ⁠<code>themes</code> and <code>⁠metadata</code> for Penpot.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">return</span> <span class="token punctuation">{</span>
  themes<span class="token punctuation">,</span>
  <span class="token literal-property property">metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">$metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">tokenSetOrder</span><span class="token operator">:</span> tokenSetOrder<span class="token punctuation">,</span>
      <span class="token literal-property property">activeThemes</span><span class="token operator">:</span> themes<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">theme</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token literal-property property">activeSets</span><span class="token operator">:</span> tokenSetOrder<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="style-dictionary-configuration" tabindex="-1">Style Dictionary Configuration</h3>
<p>We configure Style Dictionary to use the custom format for building the tokens. The token files are sourced from the 'src/tokens' directory. The output is a 'penpot.json' file built in the 'build' directory using our 'json/dtcg' custom format.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">json_combined</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'penpot.json'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'json/dtcg'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token literal-property property">nesting</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token literal-property property">global</span><span class="token operator">:</span> <span class="token string">'src/tokens/base/**/*.tokens'</span><span class="token punctuation">,</span>
              <span class="token literal-property property">semantic</span><span class="token operator">:</span> <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="build-execution" tabindex="-1">Build Execution</h3>
<p>Finally, we ensure the build directory exists, and then run the build process for the ⁠<code>json_combined</code> platform, which generates our Penpot-ready design tokens file.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> buildDir <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'build'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>buildDir<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>buildDir<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="the-penpot-ready-.json-generated-example" tabindex="-1">The Penpot-ready <code>.json</code> Generated Example</h2>
<p>After running the build script, we should have a <code>⁠penpot.json</code> file in our ⁠build directory with all our design tokens. The output should look similar to this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#cce4f6"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#b3d4ee"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffe5e5"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffcccc"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"muted"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.100.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"hover"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue.200.value}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"$themes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"default"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"default"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand a"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"brand-a"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token property">"$metadata"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"tokenSetOrder"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"base"</span><span class="token punctuation">,</span> <span class="token string">"default"</span><span class="token punctuation">,</span> <span class="token string">"brand-a"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeThemes"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/default"</span><span class="token punctuation">,</span> <span class="token string">"/brand a"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeSets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"base"</span><span class="token punctuation">,</span> <span class="token string">"default"</span><span class="token punctuation">,</span> <span class="token string">"brand-a"</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>I’ve walked through how to create a build script using Style Dictionary to generate a Penpot-ready <code>.json</code> file with all your existing design tokens. This is helpful if your ‘source of truth’ for your Design Tokens is somewhere else and Penpot is one more destination for their use. The complete code and examples for this article can be found in the <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/12-exporting-to-penpot">GitHub repository</a>.</p>
<p>As a front-end developer and a Design Systems consultant I feel I’m in a perpetual pendulum of where I think your design tokens source of truth should live. However, like most things, it kind of depends on your team, your products and your workflows. This is an option if you’re design tokens are in code, or if you’re moving towards Penpot as your design tool.</p>
<p>Regardless of where you are on your design systems journey, remember: keep iterating, keep improving, and keep exploring the tools at your disposal, just like I have done with Penpot.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Tokens have landed in Penpot, kinda</title>
      <link href="https://www.alwaystwisted.com/articles/design-tokens-in-penpot.html"/>
      <updated>2025-04-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-tokens-in-penpot.html</id>
      <content type="html">
        <![CDATA[
        <p>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).</p>
<p>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 <a href="https://penpot.app">Penpot</a>.</p>
<p>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).</p>
<p>I then spotted it, the Design Tokens panel and shifted gears.</p>
<p><img src="/images/articles/penpot/tokens-panel.jpg" alt="the design tokens panel UI for Penpot" loading="lazy" decoding="async"></p>
<p>Nice, a way to create design tokens built into the UI, including themes, sets and the tokens themselves.</p>
<p>I clicked the little plus icon next to <code>border-radius</code> and was given a popup to add a new token.</p>
<p><img src="/images/articles/penpot/border-radius.jpg" alt="the design tokens panel UI for Penpot with a popup next to is with form fields for a new token - name, value, description" loading="lazy" decoding="async"></p>
<p>Adding a new theme also had a similar pop up:</p>
<p><img src="/images/articles/penpot/new-theme.jpg" alt="a 'add new layer' popup with fields for group and theme" loading="lazy" decoding="async"></p>
<p>Adding a new set gave me something a little different:</p>
<p><img src="/images/articles/penpot/new-set.jpg" alt="the design tokens panel UI with a form input for a new set name" loading="lazy" decoding="async"></p>
<p>At the bottom of this side panel had another button that was labelled ‘tools’. I clicked it, who doesn’t click a new button.</p>
<p><img src="/images/articles/penpot/export.jpg" alt="a popup containing two items - import and export above a button titled 'tools'" loading="lazy" decoding="async"></p>
<p>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.</p>
<h2 id="to-the-documentation!" tabindex="-1">To The Documentation!</h2>
<p>I found <a href="https://help.penpot.app/user-guide/design-tokens/">documentation explaining this panel</a> (and a bit more) on their site.</p>
<p>It’s using the <a href="https://tr.designtokens.org/format/">W3C Design Tokens Community Group Draft Format</a>, it shows how you can reference tokens, what tokens you can create, edit, and use. It also introduces “Token Sets” (<a href="https://designtokens.fyi/#/terms/tier/">layers, or teirs</a> pehaps) and “Token Themes”.</p>
<h3 id="tokens" tabindex="-1">Tokens</h3>
<p>Creating a token using the UI allows you to add:</p>
<ul>
<li><strong>name:</strong> what you are naming the token (unsurprisingly). Be it <code>spacing.100</code> or <code>page.background.color</code> etc.</li>
<li><strong>value:</strong> depening on what type of token you’re creating you can apply a number or something from the available colour spaces (Hex, RGB, RGBA, ARGB, HSL or HSLA).</li>
<li><strong>description:</strong> the ability to add something meaningful to what the token does, is, or it’s intention.</li>
</ul>
<p>The available tokens (so far) are:</p>
<ul>
<li>color</li>
<li>dimensions</li>
<li>sizing</li>
<li>spacing</li>
<li>border radius</li>
<li>opacity</li>
<li>rotation</li>
</ul>
<p>(sadly, at the time of writing this, anything for typography seems to be missing. This new Design Tokens implementation is <em>brand new</em> so I hope we will see something coming soon).
As this implementation is making use of the specification you can also reference other tokens:</p>
<p><img src="/images/articles/penpot/reference-token.jpg" alt="the new token popup that shows how it is possible to reference an existing token in a new token" loading="lazy" decoding="async"></p>
<h3 id="token-sets" tabindex="-1">Token Sets</h3>
<p>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:</p>
<p><img src="/images/articles/penpot/sets.jpg" alt="a sort of folder strucutre of token sets with global and modes, modes has light and dark nested" loading="lazy" decoding="async"></p>
<h3 id="token-themes" tabindex="-1">Token Themes</h3>
<p>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:</p>
<p><img src="/images/articles/penpot/edit-theme.jpg" alt="the themes popup showing what active sets are selected" loading="lazy" decoding="async"></p>
<h3 id="creating-a-quick-example" tabindex="-1">Creating a quick example</h3>
<p>I quickly popped in some tokens, added some themes and sets and came to a UI panel like this:</p>
<p><img src="/images/articles/penpot/tokens.jpg" alt="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" loading="lazy" decoding="async"></p>
<p>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.</p>
<h2 id="but%2C-as-a-developer%E2%80%A6" tabindex="-1">But, as a developer…</h2>
<p>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 <code>.json</code> file was to export what I had.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"global"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#f44336"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffcdd2"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"radius"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"borderRadius"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"2px border rarius"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"borderRadius"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"4px border rarius"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"borderRadius"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"8px border rarius"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"borderRadius"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"16px border rarius"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"blue"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#2196f3"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"900"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#0d47a1"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"mode/light"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"mode/dark"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">""</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"$themes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand-a"</span><span class="token punctuation">,</span>
      <span class="token property">"group"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token property">"is-source"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"61d2de80-46cc-80e4-8006-030e7ccd5f46"</span><span class="token punctuation">,</span>
      <span class="token property">"modified-at"</span><span class="token operator">:</span> <span class="token string">"2025-04-10T11:39:46.156+01:00"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"mode/light"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"mode/dark"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"global"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand-b"</span><span class="token punctuation">,</span>
      <span class="token property">"group"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
      <span class="token property">"is-source"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"61d2de80-46cc-80e4-8006-031314d7f8c6"</span><span class="token punctuation">,</span>
      <span class="token property">"modified-at"</span><span class="token operator">:</span> <span class="token string">"2025-04-10T11:39:52.621+01:00"</span><span class="token punctuation">,</span>
      <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"mode/light"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"mode/dark"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
        <span class="token property">"global"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token property">"$metadata"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"tokenSetOrder"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"global"</span><span class="token punctuation">,</span> <span class="token string">"mode/light"</span><span class="token punctuation">,</span> <span class="token string">"mode/dark"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeThemes"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"/brand-a"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"activeSets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"mode/light"</span><span class="token punctuation">,</span> <span class="token string">"mode/dark"</span><span class="token punctuation">,</span> <span class="token string">"global"</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>So we get the code interpretation of the tokens I added, following the DTCGs specification using <code>$value</code>, <code>$type</code>, and <code>$description</code> and we also get some other information.</p>
<pre class="language-json"><code class="language-json"> <span class="token property">"$themes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
            <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand-a"</span><span class="token punctuation">,</span>
            <span class="token property">"group"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
            <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
            <span class="token property">"is-source"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
            <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"61d2de80-46cc-80e4-8006-030e7ccd5f46"</span><span class="token punctuation">,</span>
            <span class="token property">"modified-at"</span><span class="token operator">:</span> <span class="token string">"2025-04-10T11:39:46.156+01:00"</span><span class="token punctuation">,</span>
            <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                <span class="token property">"mode/light"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
                <span class="token property">"mode/dark"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
                <span class="token property">"global"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
            <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"brand-b"</span><span class="token punctuation">,</span>
            <span class="token property">"group"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
            <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">""</span><span class="token punctuation">,</span>
            <span class="token property">"is-source"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
            <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"61d2de80-46cc-80e4-8006-031314d7f8c6"</span><span class="token punctuation">,</span>
            <span class="token property">"modified-at"</span><span class="token operator">:</span> <span class="token string">"2025-04-10T11:39:52.621+01:00"</span><span class="token punctuation">,</span>
            <span class="token property">"selectedTokenSets"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                <span class="token property">"mode/light"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
                <span class="token property">"mode/dark"</span><span class="token operator">:</span> <span class="token string">"enabled"</span><span class="token punctuation">,</span>
                <span class="token property">"global"</span><span class="token operator">:</span> <span class="token string">"enabled"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"$metadata"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"tokenSetOrder"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"global"</span><span class="token punctuation">,</span>
            <span class="token string">"mode/light"</span><span class="token punctuation">,</span>
            <span class="token string">"mode/dark"</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"activeThemes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"/brand-a"</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"activeSets"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"mode/light"</span><span class="token punctuation">,</span>
            <span class="token string">"mode/dark"</span><span class="token punctuation">,</span>
            <span class="token string">"global"</span>
        <span class="token punctuation">]</span>
    <span class="token punctuation">}</span></code></pre>
<p>The themes seem to have some propietary <code>.json</code> for the application, but it shows us:</p>
<ul>
<li>What themes are available</li>
<li>What Token Sets each theme uses</li>
</ul>
<p>Below the themes we also get some more propietary <code>.json</code>. This <code>$metadata</code> looks like it helps the Penpot UI turn on (or off) whatever token theme and it’s token sets are active.</p>
<h2 id="a-quick-wrap-up%2C-before-part-two" tabindex="-1">A Quick Wrap Up, Before Part Two</h2>
<p>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.</p>
<p>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).</p>
<p>Creating tokens manually in the UI also feels laborious (to me) compared to code-driven workflows, and proprietary metadata fields like ⁠<code>$themes</code> can risk vendor lock-in.</p>
<p>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).</p>
<p>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).</p>
<h2 id="an-update" tabindex="-1">An update</h2>
<p>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.</p>
<ol>
<li>They are &quot;already working on composite tokens and typography is a top priority&quot;</li>
<li>&quot;A code editor is on our roadmap&quot; 👀</li>
<li>They &quot;are working to improve the current DTCG standard with themes&quot; so the metadata could be improved to &quot; provide a better experience&quot;</li>
</ol>
<p>I also noticed that, with Laura, Penpot have released <a href="https://youtu.be/f7wQXksN_kk?si=bFrSrm8rZRtz7e2P">a short video on using Design Tokens with Penpot</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 11) - Creating Sass-backed CSS Custom Properties With Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-11.html"/>
      <updated>2025-04-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-11.html</id>
      <content type="html">
        <![CDATA[
        <p>Whilst writing my recent article on <a href="https://www.alwaystwisted.com/articles/css-vs-sass">where and when I choose to use Sass variables or CSS Custom Properties</a> in a project I thought to myself <a href="https://bsky.app/profile/did:plc:mnut7bswvnl54dhflb4qofss/post/3lmcbuowvoc2p">“you could automate this bit using style dictionary”</a>. As that article is published I’ve quickly opened up a new markdown file to write this.
In this tutorial we will look at how we can use our design tokens to not only generate Sass variables, but generate CSS custom properties that will make use of the Sass variables using interpolation.</p>
<h2 id="implementing-spacing-tokens" tabindex="-1">Implementing Spacing Tokens</h2>
<p>Let's create a sample token structure that combines scale definitions with component-specific applications.
<strong>tokens/base/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.125rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.25rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"800"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/semantic/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"component"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"margin"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"inline"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.400.$value}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"block"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.400.$value}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"padding"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"inline"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.100.$value}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"block"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.100.$value}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="style-dictionary-configuration" tabindex="-1">Style Dictionary Configuration</h2>
<p>Next we need to create a new build script that will use Style Dictionary. What we want to do is:</p>
<ul>
<li>generate a <code>.scss</code> file of the base spacing tokens as Sass variables</li>
<li>generate a <code>.scss</code> file of the semantic spacing tokens that will create a set of CSS custom properties that use Sass variables via interpolations (<code>—component-margin-inline: #{$spacing-400];</code>.</li>
</ul>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span> <span class="token comment">// For file pattern matching</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Find all token files matching the pattern</span>
<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Header comment for generated files</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">// Do not edit directly, this file was auto-generated.\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary instance</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">sass_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span> <span class="token comment">// Use standard SCSS transforms</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/sass/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'_base-tokens.scss'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span> <span class="token comment">// SCSS variables format</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// Only process base tokens</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span> <span class="token comment">// Use SCSS transforms</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/sass/semantic/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.scss'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/sass-ref'</span><span class="token punctuation">,</span> <span class="token comment">// Custom format defined in hooks</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// Only process semantic tokens</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">// Custom format definitions</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">formats</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token comment">// Custom CSS format that references Sass variables</span>
      <span class="token string-property property">'css/sass-ref'</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// Process all tokens in the dictionary</span>
        <span class="token keyword">const</span> tokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens
          <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
            <span class="token keyword">const</span> isReference <span class="token operator">=</span>
              <span class="token keyword">typeof</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">&amp;&amp;</span>
              token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'{'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
              token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'}'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">const</span> sassVariable <span class="token operator">=</span> isReference
              <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">$</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value
                  <span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token comment">// Remove curly braces</span>
                  <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.\$value</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token comment">// Remove .$value suffix first</span>
                  <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token comment">// Then convert remaining dots to hyphens</span>
              <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">$</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

            <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: #{</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>sassVariable<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">};</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// Combine header, Sass import, and CSS variables</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">@use "../base/_base-tokens.scss";\n\n:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tokens<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Execute the build process for all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="key-script-components" tabindex="-1">Key Script Components</h3>
<ul>
<li><strong>Token Aggregation:</strong> Using <code>⁠globSync</code> to recursively collect all ⁠<code>.token</code>s<code> files from ⁠</code>src/tokens/*<em>/</em>.tokens`.</li>
<li><strong>Smart Reference Handling:</strong> The custom <code>⁠css/sass-ref</code> format automatically:
<ul>
<li>Detects any token reference format (⁠<code>{type.path.to.token}</code>)</li>
<li>Converts dot-notation paths to Sass-friendly hyphens</li>
<li>Removes <code>⁠. $value</code> suffixes while maintaining reference integrity</li>
</ul>
</li>
<li><strong>Separation of Concerns:</strong> Platform configuration keeps base tokens (design primitives) separate from semantic tokens (contextual applications)</li>
</ul>
<p>The code for this example can be <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/11-sass-backed-css-variables">found on this branch</a> of the repo this series has been using</p>
<h2 id="generated-output-structure" tabindex="-1">Generated Output Structure</h2>
<p>The script produces two critical files. These files are:</p>
<ul>
<li>a Sass variables file that maintains design system constants.</li>
<li>a CSS custom properties file that references Sass values via interpolation.</li>
</ul>
<h3 id="base-tokens-(sass)" tabindex="-1">Base Tokens (Sass)</h3>
<p><strong>_base-tokens.scss</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$spacing-100</span></span><span class="token punctuation">:</span> 0.125rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-200</span></span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-300</span></span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-400</span></span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-800</span></span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span></code></pre>
<h3 id="semantic-tokens-(css)" tabindex="-1">Semantic Tokens (CSS)</h3>
<p><strong>_variables.scss</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@use</span> <span class="token string">'../base/_base-tokens.scss'</span><span class="token punctuation">;</span>

<span class="token selector">:root </span><span class="token punctuation">{</span>
  <span class="token property">--component-margin-inline</span><span class="token punctuation">:</span> <span class="token variable">#{$spacing-400}</span><span class="token punctuation">;</span>
  <span class="token property">--component-margin-block</span><span class="token punctuation">:</span> <span class="token variable">#{$spacing-400}</span><span class="token punctuation">;</span>
  <span class="token property">--component-padding-inline</span><span class="token punctuation">:</span> <span class="token variable">#{$spacing-100}</span><span class="token punctuation">;</span>
  <span class="token property">--component-padding-block</span><span class="token punctuation">:</span> <span class="token variable">#{$spacing-100}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This Style Dictionary configuration helps solve several challenges in modern design systems:</p>
<ol>
<li><strong>Single Source of Truth</strong>: Token updates propagate through both Sass and CSS layers.</li>
<li><strong>Contextual Adaptation</strong>: Component-specific overrides maintain design consistency</li>
<li><strong>Toolchain Integration</strong>: Automates the Sass to CSS bridge while preserving both paradigms.</li>
<li><strong>Scale Maintenance</strong>: Spacing ratios remain consistent across primitive and semantic layers.</li>
</ol>
<p>By combining Style Dictionary's transformation power with Sass's preprocessing capabilities, we can create a future-proof system that works seamlessly with CSS-in-JS solutions, traditional Sass projects, and modern CSS-only architectures and more.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>CSS Custom Properties vs. Sass Variables: A Pragmatic Guide</title>
      <link href="https://www.alwaystwisted.com/articles/css-vs-sass.html"/>
      <updated>2025-04-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/css-vs-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>In recent articles I’ve demonstrated how we can use Design Tokens to assist with theming, be it for a <a href="">multi-brand</a> Design System or a single property that has <a href="">multiple themes</a>.<br>
If you noticed, for the multi-brand configuration we were also generating Sass variables, but it in the second article on creating multiple themes for a single site we weren’t.
I have reasons for that, as part of a strategy of when and how I use CSS custom properites or Sass variables that I’ve been implementing and refining over the last 7/8 years. I thought it would make a nice little article, so here goes.</p>
<h2 id="sass-variables%2C-css-custom-properties%2C-what%E2%80%99s-the-difference%3F" tabindex="-1">Sass Variables, CSS Custom Properties, What’s the Difference?</h2>
<p>CSS custom properties and Sass variables can seem interchangeable at first glance, but I think they excel when we look at their diverging strengths:</p>
<ul>
<li><strong>Sass variables</strong> act as <strong>compile-time constants</strong>, perfect for immutable brand guidelines and mathematical foundations.</li>
<li><strong>CSS custom properties</strong> serve as <strong>runtime-adjustable variables</strong>, enabling live theming, CMS overrides, and user-facing customisation.
I think this dichotomy shows part of modern web development’s dual demands: rigid design system governance paired with flexible contextual adaptation.
Whether you’re building a WordPress theme that content editors can tweak or an SaaS platform requiring dark mode, understanding this split can help unlock smarter architectural decisions.</li>
</ul>
<h2 id="when-i-use-css-custom-properties" tabindex="-1">When I Use CSS Custom Properties</h2>
<p>CSS custom properties are indispensable when dealing with values that can or need to adapt after the page loads. Their inherent runtime flexibility can help solve specific problems static preprocessor variables just cannot touch.</p>
<h3 id="dynamic-scenarios" tabindex="-1">Dynamic Scenarios</h3>
<h4 id="browser-runtime-changes" tabindex="-1">Browser runtime changes</h4>
<p>If you have things that can update the page live without requiring a page refresh - use CSS custom properties. Great when toggling light/dark mode or changing the overtall theme.</p>
<h4 id="user-interaction" tabindex="-1">User interaction</h4>
<p>Perhaps you have some UI the user can change that effects part of the page. Changing the value of the custom property feels cleaner, and more intuitive.</p>
<h4 id="cms%2Fback-end-control" tabindex="-1">CMS/Back-End control</h4>
<p>Have you got variants or things that you’re wanting the content creators of your site to change but don’t want to add a load of classnames or restrict the variants too much. Choose the value and create the custom property on the back-end that gets used in the browser.</p>
<h4 id="media-query-overrides" tabindex="-1">Media query overrides</h4>
<p>Simplify responsive logic. Instead of redeclaring margins at breakpoints using CSS custom properties can <a href="https://www.smashingmagazine.com/2018/05/css-custom-properties-strategy-guide/">create cleaner, more logical code</a>.</p>
<h3 id="design-system-use-cases" tabindex="-1">Design System Use Cases</h3>
<h4 id="theme-variables" tabindex="-1">Theme variables</h4>
<p>Maintain consistency while permitting exceptions. <code>--color-background: var(⁠--color-background-primary);</code> ensures brand alignment, but individual components can locally override it via <code>⁠:where(.alert) { --color-background: var(--color-background-warning; }</code> without side effects.</p>
<h4 id="runtime-computations" tabindex="-1">Runtime computations</h4>
<p>Create relationships between values. <code>⁠--icon-size: calc(var(--font-size) * 1.2);</code> could keep icons proportionally sized to text, even when users adjust font scaling.</p>
<h4 id="component-level-overrides" tabindex="-1">Component-level overrides</h4>
<p>Enable safer customisation. A ⁠card component uses ⁠<code>—card-shadow</code> internally, allowing specific instances to deviate from the global shadow system without Frankenstein CSS (<code>⁠.card--special { box-shadow: ... }</code>).</p>
<h2 id="when-i-use-sass-variables" tabindex="-1">When I Use Sass Variables</h2>
<h3 id="immutable-foundations" tabindex="-1">Immutable Foundations</h3>
<h4 id="brand-enforcement" tabindex="-1">Brand Enforcement</h4>
<p>Sass variables can help lock down design decisions that should never bend. That signature brand blue isn't just a colour – it's <code>⁠$brand-blue: #2e5eaa;</code> screaming &quot;this stays put&quot; through all of the components and layout templates being used.</p>
<h4 id="precision-math-systems" tabindex="-1">Precision Math Systems</h4>
<p>Spacing scales become architectural blueprints with Sass's compile-time calculations. While CSS variables futz with <code>⁠calc()</code> at runtime, Sass resolves ⁠<code>$spacing-unit * 1.5</code> during build – outputting clean values that can render identically in legacy IE and Chrome Canary. Although this is increasingly a moot point when wanting <a href="https://utopia.fyi/">fluid changes across browser sizes</a>.</p>
<h3 id="build-time-power-plays" tabindex="-1">Build-Time Power Plays</h3>
<h4 id="utility-class-factories" tabindex="-1">Utility Class Factories</h4>
<p>Need to provide your <a href="https://www.alwaystwisted.com/articles/creating-utility-classes-with-design-tokens-using-sass">design decisions as utility classes</a>? Sass loops can help with that (although, if you’re implementing Design Tokens you can generate these using something like Style Dictionary (I will be working on an anrticle about this as part of my <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-1">Design Tokens Workflow Series</a> soon.</p>
<h3 id="design-system-bedrock" tabindex="-1">Design System Bedrock</h3>
<h4 id="breakpoint-clarity" tabindex="-1">Breakpoint Clarity</h4>
<p>Until <a href="https://www.w3.org/TR/mediaqueries-5/#custom-mq">⁠@custom-media</a> matures and gets into browsers, Sass variables help to tame responsive chaos.</p>
<h4 id="performance-critical-math" tabindex="-1">Performance-Critical Math</h4>
<p>If you have a lot of scales for things like spacing, typography or colour perhaps you don’t want the browser to make those calculations if they’re not going to change. Using Sass will help with any possible performance issues of an over reliance on CSS custom properties for everything.</p>
<h4 id="hard-coded-themes" tabindex="-1">Hard-Coded Themes</h4>
<p>When light/dark mode gets decided at build time (CMS page type, A/B test group), Sass maps can generate lean CSS.
Sass variables thrive when values need to be <strong>set in stone</strong> after compilation. They're the mason's chisel – uncompromising, precise, and leaving no runtime debris.</p>
<h2 id="combining-both-with-a-hybrid-approach" tabindex="-1">Combining Both With A Hybrid Approach</h2>
<p>CSS custom properties and Sass variables aren't sworn enemies – they' can be great collaborators in a layered architecture.
This hybrid model can treat Sass as the source of truth and CSS variables as the delivery mechanism for runtime flexibility and at the same time allow you to “set things in stone” that will never change in Sass.
<strong>Layered Architecture</strong></p>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Purpose</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Sass Layer</strong></td>
<td>Compile-time constants</td>
<td><code>⁠$gap: 1.125rem;</code></td>
</tr>
<tr>
<td><strong>CSS Layer</strong></td>
<td>Runtime-adjustable variables</td>
<td><code>⁠--component-spacing: #{$gap};</code></td>
</tr>
</tbody>
</table>
<h2 id="a-decision-tree" tabindex="-1">A Decision Tree</h2>
<p>This isn’t about right vs. wrong – it’s about matching the tools to the needs of the design, the team, and the product.
This table isn’t perdurable and it can and does change from project to project depending on requirements I find it useful to go through at times.</p>
<table>
<thead>
<tr>
<th>Factor</th>
<th>CSS Custom Property</th>
<th>Sass Variable</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runtime changes</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>CMS exposure</td>
<td>✅</td>
<td>❌</td>
</tr>
<tr>
<td>Theming</td>
<td>✅</td>
<td>Limited</td>
</tr>
<tr>
<td>Math operations</td>
<td>Basic (⁠calc())</td>
<td>Advanced</td>
</tr>
<tr>
<td>Browser support</td>
<td>IE11+ (with polyfills)</td>
<td>Universal</td>
</tr>
</tbody>
</table>
<p>(although this is ususally thought through rather than checking an actual table).</p>
<h2 id="final-thoughts" tabindex="-1">Final Thoughts</h2>
<p>The interplay between Sass variables and CSS custom properties should be a strategic partnership. Over nearly a decade of evolving web practices, one truth persists: robust systems balance rigidity with adaptability. Sass anchors the immutable, CSS custom properties breathe life into any required fluidity.</p>
<p>Resilient systems should layer these tools intentionally. Let Sass handle the the design decisions that won’t change, heavy math and legacy support, while CSS variables manage any dynamicism required.</p>
<p>As browsers advance, the lines may blur – but the principles endure. Choose Sass for what must and should stay fixed, CSS for what needs to change.</p>
<p>After all, the best architectures aren’t built with tools, but with informed decisions about <em>when</em> to wield them.</p>
<p>(a little thanks for <a href="https://bell.bz">Andy Bell</a> for a little 'sense checking' along the way ❤️).</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 10) - Creating Multiple Themes with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-10.html"/>
      <updated>2025-04-02T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-10.html</id>
      <content type="html">
        <![CDATA[
        <p>In this tutorial series on design tokens and Style Dictionary, we have recently looked at power of <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-9">multi-brand theming</a>. Now, let's delve into creating multiple themes for a single brand.</p>
<p>Imagine having a personal website or brand that shines differently with each season, featuring special editions, or festive themes. The ability to seamlessly switch between these adds a layer of personalisation and fun engagement that can resonate with your readers.</p>
<h2 id="setting-up-token-layers-for-themes" tabindex="-1">Setting Up Token Layers for Themes</h2>
<p>Like in the <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-9">last article</a>, we will create distinct design tokens for each theme in the base layer and a single set of tokens in the semantic layer that reference the base layer.</p>
<h3 id="theme-specific-base-tokens" tabindex="-1">Theme-Specific Base Tokens</h3>
<p>For each theme, we define respective colour, typography, and spacing tokens to create visually distinct presentations. I’ll only provide the colour tokens in the article as a demonstration. You can <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/10-theming">can find all of the code in the github repo</a>.</p>
<p><strong>tokens/base/theme1/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#0D6EFD"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6C757D"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#212529"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFC107"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/theme2/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#212529"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#343A40"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#121212"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#E9ECEF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#17A2B8"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/theme3/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFC107"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F44336"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFF4E0"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#333333"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#4CAF50"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="shared-semantic-tokens" tabindex="-1">Shared Semantic Tokens</h3>
<p>The semantic tokens maintain consistency across all themes by referencing the appropriate theme base tokens, again I’ll only show the design tokens for the colours in the semantic layer also.</p>
<p><strong>tokens/semantic/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.background}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.text}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"action"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"highlight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.accent}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="configuring-style-dictionary" tabindex="-1">Configuring Style Dictionary</h2>
<p>This file organises how the tokens are processed and how the resulting CSS files are generated. Let's explore the setup:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// The themes we want to generate</span>
<span class="token keyword">const</span> themes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'theme1'</span><span class="token punctuation">,</span> <span class="token string">'theme2'</span><span class="token punctuation">,</span> <span class="token string">'theme3'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// The output formats we want to generate</span>
<span class="token keyword">const</span> formats <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'css'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">// Function to get config for a specific theme and format (theme tokens)</span>
<span class="token keyword">function</span> <span class="token function">getStyleDictionaryConfig</span><span class="token punctuation">(</span><span class="token parameter">theme<span class="token punctuation">,</span> format</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> platformConfig <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token comment">// Add theme CSS files</span>
  platformConfig<span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_theme</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> format<span class="token punctuation">,</span>
    <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">build/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/themes/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/theme-wrapper</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/base/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">themeName</span><span class="token operator">:</span> theme<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/base/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> platformConfig<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Only generate semantic once, not per theme</span>
<span class="token keyword">function</span> <span class="token function">getSemanticConfig</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">'src/tokens/base/theme1/**/*.tokens'</span><span class="token punctuation">,</span> <span class="token comment">// Need the base tokens for reference</span>
      <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_semantic</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> format<span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">build/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/semantic/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">tokens.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/variables-semantic</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Helper function to safely get token value</span>
<span class="token keyword">function</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>original <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> token<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> token<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Register custom format for CSS theme wrapper with class selector</span>
StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/theme-wrapper'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> themeName <span class="token operator">=</span> options<span class="token punctuation">.</span>themeName <span class="token operator">||</span> <span class="token string">'default'</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> tokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/base/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>themeName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Theme </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>themeName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> has </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tokens<span class="token punctuation">.</span>length<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens for theme wrapper</span><span class="token template-punctuation string">`</span></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> variables <span class="token operator">=</span> tokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> name <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>

      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>themeName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>variables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for CSS semantic variables with ds- prefix</span>
StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-semantic'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> name <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>

      <span class="token keyword">const</span> referenceValue <span class="token operator">=</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>
        <span class="token keyword">typeof</span> referenceValue <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">&amp;&amp;</span>
        referenceValue<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'{'</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> refPath <span class="token operator">=</span> referenceValue<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> cssVarName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>refPath<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVarName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>referenceValue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>variables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Loop through each theme and format and build theme tokens</span>
themes<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">theme</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  formats<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Building </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>theme<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token function">getStyleDictionaryConfig</span><span class="token punctuation">(</span>theme<span class="token punctuation">,</span> format<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// For each platform in the config</span>
    Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>sd<span class="token punctuation">.</span>config<span class="token punctuation">.</span>platforms<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      sd<span class="token punctuation">.</span><span class="token function">buildPlatform</span><span class="token punctuation">(</span>platform<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build semantic tokens once for each format</span>
formats<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Building </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> semantic tokens...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token function">getSemanticConfig</span><span class="token punctuation">(</span>format<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// For each platform in the config</span>
  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>sd<span class="token punctuation">.</span>config<span class="token punctuation">.</span>platforms<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    sd<span class="token punctuation">.</span><span class="token function">buildPlatform</span><span class="token punctuation">(</span>platform<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="key-components-of-this-configuration" tabindex="-1">Key Components of this configuration</h3>
<h4 id="creating-the-style-dictionary-instance" tabindex="-1">Creating the Style Dictionary Instance</h4>
<p>This configuration manages both theme-specific styles and a unified semantic layer. For each theme, a distinct set of base tokens is compiled. This setup allows themes to be visually unique while maintaining global consistency through central semantic tokens.</p>
<p><strong>Highlights:</strong></p>
<ul>
<li><strong>Theme-Specific Configurations</strong>: Each theme (e.g., ⁠<code>theme1</code>, <code>⁠theme2</code>, <code>⁠theme3</code>) is processed to generate a ⁠.css file wrapped in class selectors (e.g., ⁠.<code>theme1 { ... }</code>).</li>
<li><strong>Single Semantic Output</strong>: Generates a single semantic token file, ensuring consistent semantic definitions across themes.</li>
</ul>
<h4 id="custom-format-registration" tabindex="-1">Custom Format Registration</h4>
<p>The configuration includes custom formats such as <code>⁠css/theme-wrapper</code> for creating class-based CSS files and ⁠<code>css/variables-semantic</code> for generating semantically consistent variables with a ⁠<code>ds-</code> prefix.</p>
<p><strong>Highlights:</strong></p>
<ul>
<li><strong>Theme Wrappers</strong>: Theme-specific files are wrapped in class selectors, allowing easy theme switching via class manipulation.</li>
<li><strong>Consistent Semantics</strong>: Shared semantic tokens are marked with a <code>⁠ds-</code> prefix, maintaining a clear separation between base and semantic layers.</li>
</ul>
<h4 id="building-all-platforms" tabindex="-1">Building All Platforms</h4>
<p>The script loops through each theme and format, compiling the necessary CSS outputs. Maintaining structured processes ensures efficient builds and organised outputs, ready for immediate integration into modern web projects</p>
<h2 id="example-outputs" tabindex="-1">Example Outputs</h2>
<p>The Style Dictionary script creates theme-specific CSS files and a set of semantic CSS tokens that ensure stylistic consistency across themes. Here’s an example at what these outputs look like:</p>
<h3 id="generated-base-layer-css" tabindex="-1">Generated Base Layer CSS</h3>
<p>The theme-specific CSS classes are wrapped in class selectors, allowing easy switching between themes on your website by altering the class of an element (like the <code>body</code> or <code>html</code> itself):</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.theme1</span> <span class="token punctuation">{</span>
  <span class="token property">--color-base-primary</span><span class="token punctuation">:</span> #0d6efd<span class="token punctuation">;</span>
  <span class="token property">--color-base-secondary</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
  <span class="token property">--color-base-background</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--color-base-text</span><span class="token punctuation">:</span> #212529<span class="token punctuation">;</span>
  <span class="token property">--color-base-accent</span><span class="token punctuation">:</span> #ffc107<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-xs</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-sm</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-md</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-lg</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-xl</span><span class="token punctuation">:</span> 32px<span class="token punctuation">;</span>
  <span class="token property">--font-family-primary</span><span class="token punctuation">:</span> <span class="token string">'Roboto'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--font-family-secondary</span><span class="token punctuation">:</span> <span class="token string">'Open Sans'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--font-weight-regular</span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span>
  <span class="token property">--font-weight-bold</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
  <span class="token property">--font-size-small</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
  <span class="token property">--font-size-medium</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
  <span class="token property">--font-size-large</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="generated-semantic-layer-css" tabindex="-1">Generated Semantic Layer CSS</h3>
<p>This output establishes the shared semantics with a <code>ds-</code> prefix, simplifying theme maintenance. The <code>:root</code> here acts as a global baseline for semantic values:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--ds-color-background-default</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-background<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-text-default</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-highlight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-xsmall</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xs<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-small</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-sm<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-medium</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-md<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-large</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-lg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-xlarge</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xl<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-small</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-md<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-medium</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-lg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-large</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xl<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-bold<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-large<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-regular<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-medium<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-regular<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-small<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>By employing this approach, Style Dictionary can facilitate a unified and cohesive theming experience. Your themes can uniquely shine while maintaining a consistent design language across your website.
With the thematic CSS structure in place, you can integrate a theme switcher using JavaScript allowing your visitors to choose how they want to have your site look.</p>
<p>In the previous article we addressed multi-brand theming and with a few small changes this configuration has focused on tailoring multiple themes within a single brand or personal website. This approach allows you to adapt your design system to evolving needs while ensuring visual harmony.</p>
<p>Embracing these strategies provides flexible theming options to meet various needs, whether for personal projects or larger brand applications. These methods help reinforce the strength of your design system.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 9) - Implementing Multi-Brand Theming with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-9.html"/>
      <updated>2025-04-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-9.html</id>
      <content type="html">
        <![CDATA[
        <p>Businesses often juggle multiple brand identities to connect with a variety of audiences. This approach can translate into distinct visual elements (colors, typography, and other styles) that uniquely represent a brand. A robust design system is essential to juggle these brands styles while ensuring a seamless experience across all platforms.
In the last couple of tutorials in this series, we explored how to <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-7">implement light and dark modes using design tokens</a> and <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-7">strategies for managing and organising these tokens effectively</a>. This tutorial delves into the world of multi-brand theming, a critical approach that enables organisations to maintain cohesive design frameworks while embracing brand diversity.</p>
<h2 id="a-quick-recap" tabindex="-1">A quick recap</h2>
<p>For this article, we’re going to make use of <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-6">two layers of design tokens</a> to help with keeping our brands consistent when the output is being used. We will use base tokens and semantic tokens.</p>
<h3 id="base-tokens" tabindex="-1">Base Tokens</h3>
<p>Base tokens represent the raw, literal values that form the foundation of your design system. They can include:</p>
<ul>
<li>Specific hex values for colours (e.g., ⁠#BA1A2A, #006BC9)</li>
<li>Precise measurements for spacing (e.g., ⁠4px, ⁠16px)</li>
<li>Font families and weights (e.g., ⁠'Roboto', ⁠700)
Base tokens are typically named descriptively to reflect their inherent properties rather than their usage:</li>
</ul>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"blue500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007BFF"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"gray100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F5F5F5"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"4"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"16"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="semantic-tokens" tabindex="-1">Semantic Tokens</h3>
<p>Semantic tokens add meaning and context by mapping to base tokens. They can describe the purpose or usage of a token rather than its visual properties:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.blue500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.gray100}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{size.4}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{size.16}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>By using semantic tokens, teams can update the underlying base token (e.g., changing ⁠blue500 from ⁠#0066CC to #276AB3) without needing to change references throughout the codebase.</p>
<h2 id="setting-up-token-layers-for-brands" tabindex="-1">Setting Up Token Layers for Brands</h2>
<p>When implementing multiple brands, each brand requires its own set of base tokens that semantic tokens can reference. This allows you to maintain consistent semantic naming while varying the visual presentation across the brands.
Let's explore how to organise tokens for a Design System for three distinct brands:</p>
<h3 id="brand-specific-base-tokens" tabindex="-1">Brand-Specific Base Tokens</h3>
<p>For this example, we'll create dedicated sets of base tokens for each of WWE's iconic brands: Raw, SmackDown, and NXT. These tokens will encompass essential design elements such as colours, typography, and spacing, ensuring each brand maintains a unique identity while supporting a cohesive design system.
<strong>tokens/base/raw/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#d7182a"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#A3A3A3"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F5F5F5"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#1C1C1C"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFD700"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/raw/typography.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Roboto', sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Open Sans', sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"regular"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"400"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"bold"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"700"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"14px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"24px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/raw/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"24px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"32px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Now, let's define similar token files for Smackdown and NXT, each with their unique values:
<strong>tokens/base/smackdown/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#9933CC"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#495057"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F8F9FA"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#343A40"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FF5722"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/smackdown/typography.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Montserrat', sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Lato', sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"regular"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"400"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"bold"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"600"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"12px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"15px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"22px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/smackdown/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"6px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"12px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"20px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"28px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/nxt/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#2E7D32"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#546E7A"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#E8F5E9"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#1B5E20"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"accent"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F57F17"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/nxt/typography.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Poppins', sans-serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"'Merriweather', serif"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"weight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"regular"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"300"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"bold"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"500"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"18px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"26px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/base/nxt/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"5px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"10px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"20px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"30px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"40px"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="shared-semantic-tokens" tabindex="-1">Shared Semantic Tokens</h3>
<p>The key advantage of this approach is that semantic tokens can remain consistent across all themes, using a single shared naming convention with the ⁠<code>ds-</code> prefix:
<strong>tokens/semantic/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.background}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"default"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.text}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"action"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"highlight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.accent}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/semantic/typography.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"typography"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"heading"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"fontFamily"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.family.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontWeight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.weight.bold}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontSize"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.size.large}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"fontFamily"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.family.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontWeight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.weight.regular}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontSize"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.size.medium}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"caption"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"fontFamily"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.family.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontWeight"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.weight.regular}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"fontSize"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{font.size.small}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/semantic/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"element"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"xsmall"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.xs}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.sm}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.md}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.lg}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"xlarge"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.xl}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"layout"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.md}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.lg}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"large"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{spacing.base.xl}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>This structure allows you to swap out the base layer for each brand while maintaining the semantic relationships, creating a consistent naming convention regardless of which brand is being implemented.</p>
<h2 id="creating-brands-with-style-dictionary-using-token-layers" tabindex="-1">Creating Brands with Style Dictionary Using Token Layers</h2>
<p>With our token structure established, we can now configure Style Dictionary to compile brand-specific outputs while preserving the layer relationships. We'll generate both CSS custom properties and Sass variables to provide flexibility for different project requirements.</p>
<h3 id="configuring-style-dictionary" tabindex="-1">Configuring Style Dictionary</h3>
<p>The following configuration compiles our tokens into CSS and Sass outputs for each theme:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// The brands we want to generate</span>
<span class="token keyword">const</span> brands <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'raw'</span><span class="token punctuation">,</span> <span class="token string">'smackdown'</span><span class="token punctuation">,</span> <span class="token string">'nxt'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">// The output formats we want to generate</span>
<span class="token keyword">const</span> formats <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'css'</span><span class="token punctuation">,</span> <span class="token string">'scss'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token comment">// Function to get config for a specific brand and format (base tokens)</span>
<span class="token keyword">function</span> <span class="token function">getStyleDictionaryConfig</span><span class="token punctuation">(</span><span class="token parameter">brand<span class="token punctuation">,</span> format</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Base platform configuration (for both CSS and SCSS)</span>
  <span class="token keyword">const</span> platformConfig <span class="token operator">=</span> <span class="token punctuation">{</span>
    <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_base</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> format<span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">build/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/base/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>brand<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/variables</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
            token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/base/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>brand<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>

  <span class="token comment">// Removed the brand CSS files configuration here</span>

  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/base/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>brand<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> platformConfig<span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Only generate semantic once, not per brand</span>
<span class="token keyword">function</span> <span class="token function">getSemanticConfig</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">'src/tokens/base/raw/**/*.tokens'</span><span class="token punctuation">,</span> <span class="token comment">// a brand (any brand) is needed to generate semantic tokens</span>
      <span class="token string">'src/tokens/semantic/**/*.tokens'</span><span class="token punctuation">,</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_semantic</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> format<span class="token punctuation">,</span>
        <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">build/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/semantic/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token punctuation">{</span>
            <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">tokens.</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/variables-semantic</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
              <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Helper function to safely get token value</span>
<span class="token keyword">function</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>original <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>token <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> token<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> token<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// Removed the brand wrapper format registration</span>

<span class="token comment">// Register custom format for CSS semantic variables with ds- prefix</span>
StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-semantic'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> name <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>

      <span class="token keyword">const</span> referenceValue <span class="token operator">=</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>
        <span class="token keyword">typeof</span> referenceValue <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">&amp;&amp;</span>
        referenceValue<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'{'</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> refPath <span class="token operator">=</span> referenceValue<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> cssVarName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>refPath<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVarName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>referenceValue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>variables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom format for SCSS semantic variables with ds- prefix</span>
StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'scss/variables-semantic'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'src/tokens/semantic/'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> name <span class="token operator">=</span> token<span class="token punctuation">.</span>path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description <span class="token operator">||</span> <span class="token string">''</span><span class="token punctuation">;</span>

      <span class="token keyword">const</span> referenceValue <span class="token operator">=</span> <span class="token function">getTokenValue</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>
        <span class="token keyword">typeof</span> referenceValue <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">&amp;&amp;</span>
        referenceValue<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">'{'</span><span class="token punctuation">)</span>
      <span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> refPath <span class="token operator">=</span> referenceValue<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">$ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: $</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>refPath<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> // </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">$ds-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>referenceValue<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> // </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> variables<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token comment">// Loop through each brand and format and build base tokens</span>
brands<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">brand</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  formats<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Building </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> tokens for </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>brand<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token function">getStyleDictionaryConfig</span><span class="token punctuation">(</span>brand<span class="token punctuation">,</span> format<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// For each platform in the config</span>
    Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>sd<span class="token punctuation">.</span>config<span class="token punctuation">.</span>platforms<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      sd<span class="token punctuation">.</span><span class="token function">buildPlatform</span><span class="token punctuation">(</span>platform<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build semantic tokens once for each format</span>
formats<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">format</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Building </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>format<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> semantic tokens...</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sd <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token function">getSemanticConfig</span><span class="token punctuation">(</span>format<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// For each platform in the config</span>
  Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>sd<span class="token punctuation">.</span>config<span class="token punctuation">.</span>platforms<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">platform</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    sd<span class="token punctuation">.</span><span class="token function">buildPlatform</span><span class="token punctuation">(</span>platform<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="explanation-of-key-components" tabindex="-1">Explanation of Key Components</h3>
<h4 id="creating-the-style-dictionary-instance" tabindex="-1">Creating the Style Dictionary Instance</h4>
<p>This script first configures Style Dictionary to handle base tokens for multiple brands. Each brand has its own set of base tokens designated by its unique file paths in the ⁠<code>src/tokens/base/</code> directory. The script systematically builds these tokens for each brand in the specified output formats (CSS and SCSS).
<strong>Key Points:</strong></p>
<ul>
<li><strong>Brands Configuration:</strong> The ⁠<code>brands</code> array specifies the brand names, which correspond to token file directories.</li>
<li><strong>Formats:</strong> The <code>⁠formats</code> array ensures outputs for both CSS and SCSS.</li>
<li><strong>Configuration Function:</strong> ⁠<code>getStyleDictionaryConfig</code> dynamically generates the configuration for each brand and format combination.</li>
<li><strong>Token Filtering:</strong> Filters help map input token files correctly to their corresponding brands.</li>
</ul>
<h4 id="registering-a-custom-format-for-semantic-tokens" tabindex="-1">Registering a Custom Format for Semantic Tokens</h4>
<p>The script registers custom formats to generate variables with a ⁠<code>ds-</code> namespace in both CSS and SCSS. This design ensures semantic tokens remain consistent across brands, leveraging shared properties.
<strong>Highlights:</strong></p>
<ul>
<li><strong>CSS Variable Registration:</strong> Custom functions format CSS with the <code>⁠ds-</code> prefix, ensuring clarity and consistency.</li>
<li><strong>Semantic Generation:</strong> Shared semantic tokens only need to be built once, fostering efficiency.
<strong>Building All Platforms</strong>
The script uses loops to iterate over each brand and format, systematically building and compiling tokens. It ensures separate brand builds to encapsulate unique identities while generating a single semantic output, unifying shared visual elements across the system.
Finally, a console log indicates successful build completion, providing clear feedback on the process and confirming that all configurations have been executed correctly.</li>
</ul>
<h3 id="the-generated-outputs" tabindex="-1">The Generated Outputs</h3>
<p>After running the build script, Style Dictionary will generate the following files for each brand:
<strong>CSS Custom Properties (build/css/raw/base.css)</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-base-primary</span><span class="token punctuation">:</span> #d7182a<span class="token punctuation">;</span>
  <span class="token property">--color-base-secondary</span><span class="token punctuation">:</span> #8b0000<span class="token punctuation">;</span>
  <span class="token property">--color-base-background</span><span class="token punctuation">:</span> #ffcdd2<span class="token punctuation">;</span>
  <span class="token property">--color-base-text</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
  <span class="token property">--color-base-accent</span><span class="token punctuation">:</span> #ffd700<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-xs</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-sm</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-md</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-lg</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
  <span class="token property">--spacing-base-xl</span><span class="token punctuation">:</span> 32px<span class="token punctuation">;</span>
  <span class="token property">--font-family-primary</span><span class="token punctuation">:</span> <span class="token string">'Roboto'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--font-family-secondary</span><span class="token punctuation">:</span> <span class="token string">'Open Sans'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--font-weight-regular</span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span>
  <span class="token property">--font-weight-bold</span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
  <span class="token property">--font-size-small</span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
  <span class="token property">--font-size-medium</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
  <span class="token property">--font-size-large</span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>CSS Custom Properties (build/css/semantic/tokens.css)</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--ds-color-background-default</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-background<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-text-default</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-color-action-highlight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-bold<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-heading-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-large<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-regular<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-body-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-medium<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontFamily</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-family-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontWeight</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-weight-regular<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-typography-caption-fontSize</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--font-size-small<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-xsmall</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xs<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-small</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-sm<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-medium</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-md<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-large</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-lg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-element-xlarge</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xl<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-small</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-md<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-medium</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-lg<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--ds-spacing-layout-large</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--spacing-base-xl<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Sass Variables (build/scss/raw/base.scss)</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$color-base-primary</span></span><span class="token punctuation">:</span> #d7182a<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-base-secondary</span></span><span class="token punctuation">:</span> #8b0000<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-base-background</span></span><span class="token punctuation">:</span> #ffcdd2<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-base-text</span></span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-base-accent</span></span><span class="token punctuation">:</span> #ffd700<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-base-xs</span></span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-base-sm</span></span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-base-md</span></span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-base-lg</span></span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-base-xl</span></span><span class="token punctuation">:</span> 32px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-family-primary</span></span><span class="token punctuation">:</span> <span class="token string">'Roboto'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-family-secondary</span></span><span class="token punctuation">:</span> <span class="token string">'Open Sans'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-weight-regular</span></span><span class="token punctuation">:</span> 400<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-weight-bold</span></span><span class="token punctuation">:</span> 700<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-size-small</span></span><span class="token punctuation">:</span> 14px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-size-medium</span></span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$font-size-large</span></span><span class="token punctuation">:</span> 24px<span class="token punctuation">;</span></code></pre>
<p><strong>Sass Variables (build/scss/semantic/tokens.scss)</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$ds-color-background-default</span></span><span class="token punctuation">:</span> <span class="token variable">$color-base-background</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-color-text-default</span></span><span class="token punctuation">:</span> <span class="token variable">$color-base-text</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-color-action-primary</span></span><span class="token punctuation">:</span> <span class="token variable">$color-base-primary</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-color-action-secondary</span></span><span class="token punctuation">:</span> <span class="token variable">$color-base-secondary</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-color-action-highlight</span></span><span class="token punctuation">:</span> <span class="token variable">$color-base-accent</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-heading-fontFamily</span></span><span class="token punctuation">:</span> <span class="token variable">$font-family-primary</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-heading-fontWeight</span></span><span class="token punctuation">:</span> <span class="token variable">$font-weight-bold</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-heading-fontSize</span></span><span class="token punctuation">:</span> <span class="token variable">$font-size-large</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-body-fontFamily</span></span><span class="token punctuation">:</span> <span class="token variable">$font-family-secondary</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-body-fontWeight</span></span><span class="token punctuation">:</span> <span class="token variable">$font-weight-regular</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-body-fontSize</span></span><span class="token punctuation">:</span> <span class="token variable">$font-size-medium</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-caption-fontFamily</span></span><span class="token punctuation">:</span> <span class="token variable">$font-family-secondary</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-caption-fontWeight</span></span><span class="token punctuation">:</span> <span class="token variable">$font-weight-regular</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-typography-caption-fontSize</span></span><span class="token punctuation">:</span> <span class="token variable">$font-size-small</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-element-xsmall</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-xs</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-element-small</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-sm</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-element-medium</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-md</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-element-large</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-lg</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-element-xlarge</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-xl</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-layout-small</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-md</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-layout-medium</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-lg</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$ds-spacing-layout-large</span></span><span class="token punctuation">:</span> <span class="token variable">$spacing-base-xl</span><span class="token punctuation">;</span></code></pre>
<p>Similar outputs will be generated for the othrt brands, each with their unique values but maintaining the same semantic structure.</p>
<p>You can find the <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/09-multi-brand-theming">code for this article on Github</a>.</p>
<p>Using Style Dictionary for multiple brands with a token layer strategy unlocks a suite of advantages that transform how we can approach design systems.</p>
<p>Here's why this approach stands out:</p>
<ol>
<li><strong>Seamless Consistency Across Platforms</strong>: With Style Dictionary, you can produce brand-specific tokens that cater to multiple platforms such as CSS, Sass, iOS, Android, and more. This ensures a uniform visual identity is maintained across all implementations.</li>
<li><strong>Centralised Brand Management</strong>: All brand definitions are housed within a single source of truth. This centralisation simplifies the update process and minimises inconsistencies, making maintenance a breeze.</li>
<li><strong>Scalability Built-In</strong>: As your product line expands, you can incorporate new brands without overhauling your entire system. Simply add new base token sets and watch your design system grow.</li>
<li><strong>Clear License of Separation</strong>: By distinguishing between raw values and their semantic meanings, both developers and designers can work more intuitively.</li>
<li><strong>Lowered Maintenance Load</strong>: By isolating modifications to the base layer, semantic tokens inherently mirror these updates. This can reduce overhead and maintains cohesion across your brands.
By harnessing the power of Design Tokens and Style Dictionary and a layered token architecture, teams can establish resilient and maintainable multi-brand systems.
As we continue to refine and evolve our design systems, using Design Tokens and integrating Style Dictionary presents a robust route toward flexible and scalable branding solutions. Stay tuned for our next installment, where we will dive into creating multiple themes for a single brand.</li>
</ol>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 8) - Implementing Light and Dark Mode with Style Dictionary (part 2)</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-8.html"/>
      <updated>2025-03-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-8.html</id>
      <content type="html">
        <![CDATA[
        <p>In the last article in this series <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-7">we looked at how we could convert our design tokens into CSS for light and dark modes using Style Dictionary</a>. We created some new formats to generate CSS that used <code>prefers-color-scheme</code> and also generate separate CSS files for both light and dark mode or a single CSS file that would incorporate both.
In this tutorial, we will explore two additional methods for implementing light and dark modes in your design system using Style Dictionary. Building on our previous tutorial, we will focus on how to add a data attribute or CSS class for dark mode, as well as generating relevant tokens using the CSS <code>light-dark()</code> function. These approaches enhance the flexibility and adaptability of your design system, allowing for a smoother user experience.</p>
<h2 id="adding-a-data-attribute-or-css-class-for-dark-mode" tabindex="-1">Adding a Data Attribute or CSS Class for Dark Mode</h2>
<p>To provide users with a seamless experience when toggling between light and dark modes, we can utilise a data attribute or CSS class. This method allows developers to apply dark mode styles conditionally based on the presence of a specific attribute or class in the HTML. Additionally, developers can implement a JavaScript function to toggle these modes dynamically, enabling users to switch modes with a button click.</p>
<h3 id="creating-some-design-tokens" tabindex="-1">Creating Some Design Tokens</h3>
<p>Again, we will have some base <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-6">layer tokens</a> to choose from at the semantic layer to provide meaningful, purposeful names for the design decisions for light and dark mode.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"white"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"black"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"gray"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F7F7F7"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#E1E1E1"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#CFCFCF"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#B3B3B3"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#A0A0A0"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"600"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#7D7D7D"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#5A5A5A"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"800"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#3D3D3D"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"900"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#1A1A1A"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007BFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6C757D"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>We will then setup our semantic tokens like we did for <a href="localhost:8080/articles/a-design-tokens-workflow-part-7.html%23single-token-file-incorporating-light-and-dark-modes-(one-css-file)">single token file</a> in the last article in this series.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.black}"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.black}"</span><span class="token punctuation">,</span>
      <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"card"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.200}"</span><span class="token punctuation">,</span>
        <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.800}"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for cards in light mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"border"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.600}"</span><span class="token punctuation">,</span>
        <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.400}"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Border color for cards in light mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary button background color in dark mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Secondary button background color in dark mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for buttons in dark mode."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="setting-up-the-build-process" tabindex="-1">Setting Up the Build Process</h3>
<p>We now need to set up the script that sets up the build process for generating CSS variables that accommodate both light and dark modes, including the necessary data attribute and CSS class.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
 * Do not edit directly, this file was auto-generated.
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_themed</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/combined/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-themed'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-themed'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'combined'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
    <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
    <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> lightCssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> darkModeValue <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$mods<span class="token operator">?.</span>dark<span class="token punctuation">;</span>
    <span class="token keyword">const</span> darkCssVariableName <span class="token operator">=</span> darkModeValue
      <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkModeValue
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span>
      <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">light</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      <span class="token literal-property property">dark</span><span class="token operator">:</span> darkCssVariableName
        <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
        <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> lightVariables <span class="token operator">=</span> variables<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">v</span><span class="token punctuation">)</span> <span class="token operator">=></span> v<span class="token punctuation">.</span>light<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkVariables <span class="token operator">=</span> variables
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">v</span><span class="token punctuation">)</span> <span class="token operator">=></span> v<span class="token punctuation">.</span>dark<span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root  {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}\n\n@media (prefers-color-scheme: dark) {\n  :root{\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}\n\n[data-mode='dark'], .mode-dark {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="explanation-of-the-script" tabindex="-1">Explanation of the Script</h3>
<ol>
<li><strong>Data Attribute and CSS Class</strong>: The generated CSS will include styles that apply when a [data-mode='dark'] attribute or a .mode-dark class is present. This provides flexibility in how dark mode styles are applied, allowing developers to choose the method that best fits their project.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// Data Attribute and CSS Class</span>
<span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root  {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}\n\n@media (prefers-color-scheme: dark) {\n  :root{\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}\n\n[data-mode='dark'], .mode-dark {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
<ol start="2">
<li><strong>CSS Variable Generation</strong>: The script extracts semantic tokens and generates CSS variables for both light and dark modes. The dark mode variables are included within a media query for automatic application based on user preferences, while also being available for manual toggling via the data attribute or class.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// CSS Variable Generation</span>
<span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
  <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
  <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> lightCssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkModeValue <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$mods<span class="token operator">?.</span>dark<span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkCssVariableName <span class="token operator">=</span> darkModeValue
    <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkModeValue
        <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span>
    <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">light</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token literal-property property">dark</span><span class="token operator">:</span> darkCssVariableName
      <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
      <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="the-generated-css" tabindex="-1">The Generated CSS</h3>
<p>After running this build script, Style Dictionary will generate one CSS file for the colours in the semantic tokens layer. We now have CSS declarations that are nested within a data-attribute and CSS class.
This script also provides both ⁠prefers-color-scheme CSS declarations and styles based on data attributes or CSS classes, ensuring a comprehensive approach to theming. While the media query automatically detects user preferences for light or dark mode, the data attribute and CSS class allow users to manually toggle modes (using JavaScript).</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-200<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-600<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-800<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token selector">[data-mode='dark'],
.mode-dark</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-800<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="generating-the-relevant-tokens-in-the-css-light-dark()-function" tabindex="-1">Generating the Relevant Tokens in the CSS light-dark() Function</h2>
<p>Another effective method for managing light and dark modes is to utilise a <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark">light-dark()</a> function in CSS. This function simplifies the process of switching between light and dark mode styles, allowing developers to specify how styles should adapt based on the user's preference</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><a href="https://front-end.social/@sarajw">Sara Joy</a> has an excellent article on CSS-Tricks explaining the wonders of the <a href="https://css-tricks.com/come-to-the-light-dark-side/">light-dark() CSS function</a></p>
</div></div>
<h3 id="setting-up-the-build-process-1" tabindex="-1">Setting Up the Build Process</h3>
<p>Here’s how to implement the light-dark() function in your CSS:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
 * Do not edit directly, this file was auto-generated.
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_themed</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/combined/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-themed'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-themed'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'combined'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> lightCssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> darkModeValue <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$mods<span class="token operator">?.</span>dark<span class="token punctuation">;</span>
      <span class="token keyword">const</span> darkCssVariableName <span class="token operator">=</span> darkModeValue
        <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkModeValue
            <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span>
        <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

      <span class="token keyword">if</span> <span class="token punctuation">(</span>darkCssVariableName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: light-dark(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">);</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>variables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="explanation-of-the-script-1" tabindex="-1">Explanation of the Script</h3>
<ol>
<li><strong>light-dark() Function</strong>: The light-dark() function takes two parameters: the light mode variable and the dark mode variable. This allows for a concise way to define styles that adapt based on the user's preference, making it easier to manage changes in themes without duplicating styles.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>darkCssVariableName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: light-dark(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">);</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<ol start="2">
<li><strong>CSS Variable Generation</strong>: Similar to the previous script, this one extracts semantic tokens and generates CSS variables. The key difference is the use of the light-dark() function, which simplifies the CSS output and enhances readability.</li>
</ol>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> variables <span class="token operator">=</span> semanticTokens
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
    <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
    <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> lightCssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> darkModeValue <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$mods<span class="token operator">?.</span>dark<span class="token punctuation">;</span>
    <span class="token keyword">const</span> darkCssVariableName <span class="token operator">=</span> darkModeValue
      <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkModeValue
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span>
      <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

    <span class="token comment">// Use light-dark() function for dark mode variables</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>darkCssVariableName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: light-dark(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">);</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightCssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="the-generated-css-1" tabindex="-1">The Generated CSS</h3>
<p>After running this script we get a single CSS file for the colours that were in the semantic layer of the design tokens.</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">light-dark</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">light-dark</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">light-dark</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-200<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-800<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">light-dark</span><span class="token punctuation">(</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-600<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-400<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>In [the first article, we discussed <a href="http://localhost:8080/articles/a-design-tokens-workflow-part-7.html#single-token-file-incorporating-light-and-dark-modes-(one-css-file)">various methods for implementing light and dark modes using design tokens with Style Dictionary</a>. Building on that foundation, here are five effective ways to generate CSS for light and dark modes:</p>
<ol>
<li><strong>Multiple Files for Light and Dark Modes (Two CSS Files)</strong>: Create separate token files for light and dark modes, generating distinct CSS files for each mode. This ensures clear separation and easy management of styles, allowing for straightforward updates and maintenance. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Multiple Files for Light and Dark Modes (One CSS File)</strong>: Generate a single CSS file that consolidates styles for both light and dark modes. This method utilises the prefers-color-scheme media feature to apply the appropriate styles based on user preferences, providing a seamless experience. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07a-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Single Token File Incorporating Light and Dark Modes (One CSS File)</strong>: Author a single token file that contains both light and dark mode styles. This approach allows for a cohesive view of design tokens and facilitates easier management and updates, generating a single CSS file that includes all necessary styles. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07b-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Data Attribute or CSS Class for Dark Mode</strong>: Implement a data attribute or CSS class to enable manual toggling between light and dark modes. This method allows developers to conditionally apply dark mode styles based on the presence of a specific attribute or class in the HTML, enhancing user customization. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/08-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Using the CSS</strong> light-dark() <strong>Function</strong>: Leverage the CSS light-dark() function to define styles that adapt based on user preferences. This function simplifies the process of switching between light and dark mode styles, allowing developers to specify how styles should adjust without duplicating code.<a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/08a-light-and-dark-mode">View on GitHub</a></li>
</ol>
<p>These methods provide flexibility and adaptability in your design system, ensuring that users have a smooth and personalized experience when interacting with your application.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 7) - Implementing Light and Dark Mode with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-7.html"/>
      <updated>2025-03-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-7.html</id>
      <content type="html">
        <![CDATA[
        <p>In this tutorial, we will explore how to implement light and dark modes in your design system using design tokens with Style Dictionary. We've previously covered formats, value conversion, extending the design tokens format, and design token layers in earlier tutorials. Today, we will build upon those concepts to effectively manage design tokens for both modes and generate the necessary CSS to ensure a seamless transition.</p>
<h2 id="a-quick-look-at-dark-and-light-mode" tabindex="-1">A Quick Look at Dark and Light Mode</h2>
<p>With the introduction of the ~<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme">prefers-color-scheme</a>~ media feature, websites can now provide additional theming options for their visitors by implementing ‘dark mode’ and ‘light mode’. Light mode typically features a bright background with dark text, which is well-suited for use in well-lit environments. Conversely, dark mode employs a dark background with light text, creating a visually comfortable experience for users in low-light conditions. This mode not only reduces eye strain but also enhances readability, making it a popular choice for many applications.
The ability to toggle between these modes has become increasingly important as users seek personalised experiences that cater to their preferences and environments. By leveraging the prefers-color-scheme media query, we can automatically adjust styles based on the user's system settings, ensuring a seamless transition between modes. This adaptability is crucial for modern design systems, as it enhances user satisfaction and accessibility.</p>
<h3 id="the-role-of-design-tokens" tabindex="-1">The Role of Design Tokens</h3>
<p>Design tokens provide a consistent and reusable framework for defining colours, spacing, and other design attributes, facilitating easy management and switching between modes without the need to rewrite styles or adjust individual components. For instance, semantic tokens can be created to specify background and text colours for both light and dark modes, allowing for a seamless transition based on user preferences.
Moreover, design tokens facilitate scalability and maintainability within a design system. By using a single source of truth for colours and styles, teams can ensure that updates to the design are applied uniformly across all components. This consistency is particularly important when implementing light and dark modes, as it helps maintain visual harmony and accessibility across different modes. With design tokens, adjusting the appearance of an entire application becomes a straightforward process, enhancing user experience and satisfaction.</p>
<h2 id="ways-to-author-design-tokens" tabindex="-1">Ways to Author Design Tokens</h2>
<p>In this article, we will explore three methods for creating CSS for light and dark modes using design tokens. Each approach offers unique advantages and can be tailored to fit the needs of your design system.</p>
<ol>
<li><strong>Multiple Files for Light and Dark Modes (Two CSS Files)</strong>: In this method, we will create separate token files for light and dark modes. This setup allows us to generate two distinct CSS files, one for each mode, ensuring clear separation and easy management of styles. Each file will reference its corresponding semantic tokens, making it straightforward to maintain and update styles.</li>
<li><strong>Multiple Files for Light and Dark Modes (One CSS File)</strong>: Similar to the first method, this approach also involves creating separate token files for light and dark modes. However, in this case, we will generate a single CSS file that incorporates styles from both modes. This can be achieved using the prefers-color-scheme media feature to apply the appropriate styles based on user preferences.</li>
<li><strong>Single Token File Incorporating Light and Dark Modes (One CSS File)</strong>: In this approach, we will author a single token file that contains both light and dark mode styles. This method allows for a more cohesive view of the design tokens, facilitating easier management and updates. We will then generate a single CSS file that includes all necessary styles, using a combination of CSS custom properties and media queries to handle the mode switching.
By exploring these three methods, we can demonstrate the flexibility and power of design tokens in managing light and dark modes effectively. Now, let’s dive into the code examples for each approach.</li>
</ol>
<h2 id="getting-started" tabindex="-1">Getting Started</h2>
<p>First, we will look at the multiple JSON files we need to create to generate the appropriate CSS files.</p>
<h3 id="creating-some-design-tokens" tabindex="-1">Creating some Design Tokens</h3>
<p><strong>Base Tokens</strong>
Base tokens are the fundamental building blocks of your design system. They represent the raw, literal values that define colours, spacing, typography, and more. Let's create a short set of base tokens that we can reference to create our light and dark modes.
<strong>tokens/base/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"white"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFFFFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"black"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#000000"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"gray"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"100"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#F7F7F7"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"200"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#E1E1E1"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"300"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#CFCFCF"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#B3B3B3"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"500"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#A0A0A0"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"600"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#7D7D7D"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"700"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#5A5A5A"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"800"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#3D3D3D"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"900"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#1A1A1A"</span><span class="token punctuation">,</span>
          <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007BFF"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6C757D"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Semantic Tokens</strong>
Now that we've got a simple set of base tokens, we can build on these with semantic tokens, which provide context and meaning. They map to the base tokens and define how these colours should be used in different modes. To effectively manage light and dark modes, we can create separate semantic token files—one for light mode and one for dark mode.
<strong>tokens/semantic/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.black}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"card"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.200}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for cards in light mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"border"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.600}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Border color for cards in light mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary button background color in dark mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Secondary button background color in dark mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for buttons in dark mode."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>tokens/semantic/colors.dark.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.500}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for dark mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for dark mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"card"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.800}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for cards in dark mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"border"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.500}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Border color for cards in dark mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>In this structure, we have separate semantic token files for light and dark modes:</p>
<ul>
<li><strong>Background tokens</strong> define the primary background colour for each mode.</li>
<li><strong>Text tokens</strong> specify the colour of the text based on the mode.</li>
<li><strong>Card tokens</strong> provide specific styles for card components, with background and border colours defined for light mode using ⁠{colour.gray.200} and ⁠{colour.gray.600}, and for dark mode using ⁠{colour.gray.800} and ⁠{colour.gray.500}.</li>
<li><strong>Button tokens</strong> specify the background colours for primary and secondary buttons in both modes, ensuring that the appropriate styles are applied based on the selected mode.
This structure, with separate files for light and dark modes, helps maintain clarity and consistency across your design system. It makes it easier to manage colour transitions between modes and ensures a cohesive user experience. |</li>
</ul>
<h2 id="setting-up-style-dictionary" tabindex="-1">Setting Up Style Dictionary</h2>
<p>We need to create a ⁠build.js (or config, or whatever you like to call it) file to set up Style Dictionary to manage these design tokens for light and dark modes. The file will define how the tokens are processed and how the resulting CSS files are generated. Below is the complete code for the ⁠build.js file, followed by an explanation of its key components.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
 * Do not edit directly, this file was auto-generated.
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/semantic/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.dark.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-dark'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
            token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-dark'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> outputReferences <span class="token punctuation">}</span> <span class="token operator">=</span> options<span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
      token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> tokens <span class="token operator">=</span> darkTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove curly braces</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">@media (prefers-color-scheme: dark) {\n  :root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tokens<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now let’s look at a couple of key parts of this JavaScript file:</p>
<h3 id="creating-the-style-dictionary-instance" tabindex="-1">Creating the Style Dictionary Instance</h3>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/semantic/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.dark.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-dark'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
            token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In this section, we create a new instance of ⁠StyleDictionary and configure it to manage our token files. The configuration is divided into two main platforms:</p>
<ol>
<li><strong>css_base</strong>: This platform generates a CSS file (⁠colors.css) for base tokens. The filter ensures that only tokens from the base category are included in this file.</li>
<li><strong>css_semantic</strong>: This platform generates CSS files for semantic tokens. It includes:
<ul>
<li>A <code>⁠colors.cs</code>s file for general semantic tokens. This uses Style Dictionary’s <code>filter</code> so we can only generate tokens from the files that are in the folder ‘semantic’.</li>
<li>A <code>⁠colors.dark.css</code> file specifically for dark mode tokens, using the ⁠variables-dark format. Again this uses Style Dictionary’s <code>filter</code> to look for tokens in the ‘semantic’ folder and also looks for ‘dark’ in the file name. We also use a custom format to compile the tokens to the CSS that we need.</li>
</ul>
</li>
</ol>
<h3 id="registering-the-%E2%81%A0variables-dark-format" tabindex="-1">Registering the ⁠variables-dark Format</h3>
<pre class="language-js"><code class="language-js">StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-dark'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> outputReferences <span class="token punctuation">}</span> <span class="token operator">=</span> options<span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
      token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> tokens <span class="token operator">=</span> darkTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Remove curly braces</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">@media (prefers-color-scheme: dark) {\n  :root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tokens<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This custom format for <code>⁠variables-dark</code> generates CSS custom properties specifically for dark mode. Here’s how it works:</p>
<ul>
<li>The function filters the tokens to include only those that are semantic and marked for dark mode.</li>
<li>It then maps these tokens to create CSS variable declarations, transforming the token names into valid CSS variable names.</li>
<li>The output is wrapped in a media query that applies the styles only when the user prefers dark mode, ensuring that the CSS is conditionally applied based on user settings.</li>
</ul>
<h3 id="building-all-platforms" tabindex="-1">Building All Platforms</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Finally, this line triggers the build process for all configured platforms, generating the necessary CSS files based on the defined tokens and formats. The console log confirms that the build has completed successfully.</p>
<h2 id="the-generated-css" tabindex="-1">The Generated CSS</h2>
<p>After running the build process, Style Dictionary generates several CSS files based on the defined tokens and formats. Here’s a breakdown of the outputs:
<strong>base/colors.css</strong>
This file contains the base colour tokens defined in your design system. It establishes CSS custom properties (variables) that represent fundamental colours used throughout your application. The output looks like this:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-base-white</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--color-base-black</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-100</span><span class="token punctuation">:</span> #f7f7f7<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-200</span><span class="token punctuation">:</span> #e1e1e1<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-300</span><span class="token punctuation">:</span> #cfcfcf<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-400</span><span class="token punctuation">:</span> #b3b3b3<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-500</span><span class="token punctuation">:</span> #a0a0a0<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-600</span><span class="token punctuation">:</span> #7d7d7d<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-700</span><span class="token punctuation">:</span> #5a5a5a<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-800</span><span class="token punctuation">:</span> #3d3d3d<span class="token punctuation">;</span>
  <span class="token property">--color-base-gray-900</span><span class="token punctuation">:</span> #1a1a1a<span class="token punctuation">;</span>
  <span class="token property">--color-base-primary</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--color-base-secondary</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>These variables can be used throughout your CSS to maintain consistency in colour usage across different components (this will be the same CSS file for the other two examples also, so I won’t repeat it).
<strong>semantic/colors.css</strong>
This file contains the semantic colour tokens that define how the base colours should be applied in the context of your design system. It specifies colours for light and dark modes, ensuring that the appropriate styles are applied based on the chosen mode. The output includes:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-gray-500
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for dark mode. */</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for dark mode. */</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-gray-800
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for cards in dark mode. */</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-gray-500
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Border color for cards in dark mode. */</span>
  <span class="token property">--button-background-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-primary
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Primary button background color in dark mode. */</span>
  <span class="token property">--button-background-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-secondary
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Secondary button background color in dark mode. */</span>
  <span class="token property">--button-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-white
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for buttons in dark mode. */</span>
<span class="token punctuation">}</span></code></pre>
<p>This file allows for easy management of colours specific to different components and contexts, ensuring that they adapt correctly to the selected mode.
<strong>semantic/colors.dark.css</strong>
This file is specifically for dark mode and uses the ⁠prefers-color-scheme media query to apply styles conditionally based on user preferences. The output looks like this:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-gray-500
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for dark mode. */</span>
    <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for dark mode. */</span>
    <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-gray-800
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for cards in dark mode. */</span>
    <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-gray-500
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Border color for cards in dark mode. */</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The styles defined here will only be applied when the user’s system is set to dark mode, ensuring that the application responds to user preferences and provides a comfortable viewing experience.</p>
<h2 id="multiple-files-for-light-and-dark-modes-(one-css-file)" tabindex="-1">Multiple Files for Light and Dark Modes (One CSS File)</h2>
<p>In this approach, we will create separate token files for light and dark modes, but instead of generating two distinct CSS files, we will consolidate the styles into a single CSS file. This method allows us to leverage the prefers-color-scheme media feature to apply the appropriate styles based on user preferences seamlessly.</p>
<h3 id="setting-up-the-build-process" tabindex="-1">Setting Up the Build Process</h3>
<p>To implement this method, we will modify our build.js file to include a new format that combines the light and dark mode styles into one CSS file. Below is the complete code for the updated build.js file, followed by an explanation of its key components.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
* Do not edit directly, this file was auto-generated.
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/semantic/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-combined'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-combined'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> outputReferences <span class="token punctuation">}</span> <span class="token operator">=</span> options<span class="token punctuation">;</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
      token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> semanticVariables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> comment <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> darkVariables <span class="token operator">=</span> darkTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> comment <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>semanticVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="key-components-of-the-build-process" tabindex="-1">Key Components of the Build Process</h3>
<p><strong>Creating the Style Dictionary Instance</strong></p>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/semantic/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-combined'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>In this section, we configure a new instance of StyleDictionary to manage our token files. The configuration includes two main platforms:</p>
<ol>
<li>css_base: This platform generates a CSS file (colors.css) for base tokens, ensuring that only base category tokens are included.</li>
<li>css_semantic: This platform generates a single CSS file for semantic tokens, utilising the new css/variables-combined format.</li>
</ol>
<p><strong>Registering the variables-combined Format</strong></p>
<pre class="language-javascript"><code class="language-javascript">StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-combined'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> outputReferences <span class="token punctuation">}</span> <span class="token operator">=</span> options<span class="token punctuation">;</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> darkTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>
    <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
      token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'dark'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> semanticVariables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> comment <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> darkVariables <span class="token operator">=</span> darkTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> comment <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>comment<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>semanticVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The custom format for variables-combined generates CSS custom properties for both light and dark modes in a single file. Here’s how it works:</p>
<ul>
<li>Token Filtering: The function filters the tokens to include all semantic tokens and those specifically marked for dark mode.</li>
<li>Variable Mapping: It maps the semantic tokens to create CSS variable declarations, transforming token names into valid CSS variable names.</li>
<li>CSS Output: The output is structured to include a root declaration for light mode styles, followed by a media query for dark mode styles.</li>
</ul>
<h3 id="the-generated-css-1" tabindex="-1">The Generated CSS</h3>
<p>After running the build process, Style Dictionary generates a single CSS file that incorporates styles for both light and dark modes. Here’s a breakdown of the output:</p>
<p><strong>semantic/colors.css</strong></p>
<p>This file contains the combined CSS custom properties for light and dark modes, utilising the prefers-color-scheme media query. The output looks like this:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
* Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-500<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-800<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-500<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-primary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-background-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-secondary<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--button-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-500<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-800<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-gray-500<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="single-token-file-incorporating-light-and-dark-modes-(one-css-file)" tabindex="-1">Single Token File Incorporating Light and Dark Modes (One CSS File)</h2>
<p>In this approach, we will author a single token file that contains both light and dark mode styles. This method allows for a more cohesive view of the design tokens, facilitating easier management and updates. We will then generate a single CSS file that includes all necessary styles, using a combination of CSS custom properties and media queries to handle the mode switching.</p>
<h3 id="creating-the-design-tokens" tabindex="-1">Creating the Design Tokens</h3>
<p>Here’s an example of how the token file can be structured to incorporate both light and dark mode styles:</p>
<p><strong>tokens/semantic/colors.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.black}"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.black}"</span><span class="token punctuation">,</span>
      <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for light mode."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"card"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.200}"</span><span class="token punctuation">,</span>
        <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.800}"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Background color for cards in light mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"border"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.600}"</span><span class="token punctuation">,</span>
        <span class="token property">"$mods"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"dark"</span><span class="token operator">:</span> <span class="token string">"{color.base.gray.400}"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Border color for cards in light mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"button"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.primary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Primary button background color in dark mode."</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.secondary}"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
        <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Secondary button background color in dark mode."</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.base.white}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Text color for buttons in dark mode."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>You will notice in this <code>.tokens</code> file that we have introduce the <code>$mode</code> thing so that we can define additional values for things like dark mode or high contrast mode. This is (for now, possibly) not part of the specification, it comes from <a href="https://github.com/amzn/style-dictionary/issues/1171">this (closed) github issue</a> and I liked it 😊.</p>
<h3 id="setting-up-the-build-process-1" tabindex="-1">Setting Up the Build Process</h3>
<p>To implement this method, we will modify our build.js file to include logic that handles both light and dark mode styles from a single token file. Below is the complete code for the updated build.js file, followed by an explanation of its key components.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">HEADER_COMMENT</span> <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/**
 * Do not edit directly, this file was auto-generated.
 */\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css_base</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/base/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">css_semantic</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/combined/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'colors.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables-combined'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span>hooks<span class="token punctuation">.</span>formats<span class="token punctuation">[</span><span class="token string">'css/variables-combined'</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>
  dictionary<span class="token punctuation">,</span>
  options<span class="token punctuation">,</span>
<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> semanticTokens <span class="token operator">=</span> dictionary<span class="token punctuation">.</span>allTokens<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
    token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'combined'</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> lightVariables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
      <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">[</span><span class="token string">'$value'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> darkVariables <span class="token operator">=</span> semanticTokens
    <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> token<span class="token punctuation">;</span>
      <span class="token keyword">const</span> description <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$description<span class="token punctuation">;</span>
      <span class="token keyword">const</span> darkModeValue <span class="token operator">=</span> token<span class="token punctuation">.</span>original<span class="token punctuation">.</span>$mods<span class="token operator">?.</span>dark<span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>darkModeValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> baseVariableName <span class="token operator">=</span> darkModeValue<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^\{|\}$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> cssVariableName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">var(--</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>baseVariableName<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">_</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">  --</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cssVariableName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> /* </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> */</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span>
    <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">HEADER_COMMENT</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">:root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>lightVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>darkVariables<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n  }\n}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="key-components-of-the-build-process-1" tabindex="-1">Key Components of the Build Process</h3>
<p>1. Creating the Style Dictionary Instance:</p>
<ul>
<li>This instance is configured to manage our token files, including a platform for base tokens and a platform for semantic tokens that utilise the new css/variables-combined format.</li>
</ul>
<ol start="2">
<li>Registering the variables-combined Format:</li>
</ol>
<ul>
<li>This custom format generates CSS custom properties for both light and dark modes from a single token file.</li>
<li>It filters the tokens to extract both light mode values and dark mode overrides using the $mods property.</li>
<li>The output is structured to include a root declaration for light mode styles, followed by a media query for dark mode styles.</li>
</ul>
<h3 id="the-generated-css-2" tabindex="-1">The Generated CSS</h3>
<p>After running the build process, Style Dictionary (again) generates a single CSS file that incorporates styles for both light and dark modes. Here’s a breakdown of the output:</p>
<p><strong>semantic/colors.css</strong></p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-white
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for light mode. */</span>
  <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-black<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for light mode. */</span>
  <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-gray-200
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for cards in light mode. */</span>
  <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-gray-600
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Border color for cards in light mode. */</span>
  <span class="token property">--button-background-primary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-primary
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Primary button background color in dark mode. */</span>
  <span class="token property">--button-background-secondary</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-secondary
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Secondary button background color in dark mode. */</span>
  <span class="token property">--button-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
    --color-base-white
  <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for buttons in dark mode. */</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-black
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for dark mode. */</span>
    <span class="token property">--color-text</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-base-white<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Text color for dark mode. */</span>
    <span class="token property">--color-card-background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-gray-800
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Background color for cards in dark mode. */</span>
    <span class="token property">--color-card-border</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>
      --color-base-gray-400
    <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* Border color for cards in dark mode. */</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Implementing light and dark modes using design tokens with Style Dictionary enhances user experience and adaptability. This article explored three effective methods for managing design tokens, providing flexibility in your design system.</p>
<ol>
<li><strong>Multiple Files for Light and Dark Modes (Two CSS Files)</strong>: This approach allows for clear separation of styles, generating distinct CSS files for each mode. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Multiple Files for Light and Dark Modes (One CSS File)</strong>: By consolidating styles into a single CSS file, this method leverages the ⁠prefers-color-scheme media feature to adapt based on user preferences. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07a-light-and-dark-mode">View on GitHub</a></li>
<li><strong>Single Token File Incorporating Light and Dark Modes (One CSS File)</strong>: This cohesive approach simplifies management by using a single token file that includes both light and dark mode styles, facilitating easier updates and maintenance. <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/07b-light-and-dark-mode">View on GitHub</a></li>
</ol>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sponsorship Opportunities for the Design Systems Newsletter</title>
      <link href="https://www.alwaystwisted.com/articles/sponsorship-opportunities-for-the-design-systems-newsletter.html"/>
      <updated>2025-02-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sponsorship-opportunities-for-the-design-systems-newsletter.html</id>
      <content type="html">
        <![CDATA[
        <p>I’m thrilled to announce that the <a href="https://news.design.systems"><strong>Design Systems Newsletter</strong></a> is now open for sponsorship!</p>
<p>With over <strong>3,700 subscribers</strong> and an impressive average open rate of <strong>54%</strong> and click-through rate of <strong>16%</strong>, this newsletter reaches a highly engaged audience that values quality content.</p>
<h3 id="why-sponsorship%3F" tabindex="-1">Why Sponsorship?</h3>
<p>As the newsletter continues to grow, sponsorship will help cover costs and support the time dedicated to curating the best articles and resources for our readers.</p>
<p>I’m looking for sponsorship from companies and folks that work in and around the <strong>Design Systems</strong> space or have products that could support the designers or developers who work on design systems.</p>
<h3 id="sponsorship-details" tabindex="-1">Sponsorship Details</h3>
<ul>
<li><strong>Cost</strong>: £200 per issue</li>
<li><strong>Frequency</strong>: Issues may be sporadic, with a maximum frequency of weekly releases. I prioritise sharing only the most valuable content, so newsletters will be sent out when there’s enough to share.</li>
<li><strong>Payment Terms</strong>: &quot;Pay before you play.&quot; Sponsorship fees are required upfront prior to the newsletter being sent out.</li>
</ul>
<h3 id="advertisement-placement" tabindex="-1">Advertisement Placement</h3>
<ul>
<li>The advertisement will be <strong>text-only</strong> and placed at the end of the newsletter.</li>
<li>Additionally, it will also be featured on the <strong>archive site</strong> as part of the newsletter, providing extended visibility for your brand.</li>
</ul>
<h3 id="about-me" tabindex="-1">About Me</h3>
<p>I am also seeking work opportunities as a <strong>front-end developer</strong> and a dedicated <strong>design systems advocate</strong>. With over <strong>12 years of experience</strong>, I have helped organisations and teams create and maintain effective design systems, and I enjoy teaching advanced <strong>Sass</strong> and <strong>CSS techniques</strong>.</p>
<p>If you’re interested in sponsoring the Design Systems newsletter or if you have potential work opportunities, please feel free to <a href="http://www.alwaystwisted.com/contact">reach out</a>. I look forward to collaborating and creating impactful content together!</p>
<p>Alternatively, you can help me by <a href="https://buymeacoffee.com/sturobson">buying me a coffee</a>.</p>
<p>🙏🖤</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Adding Random Content Using Eleventy</title>
      <link href="https://www.alwaystwisted.com/articles/random-content-using-eleventy.html"/>
      <updated>2024-12-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/random-content-using-eleventy.html</id>
      <content type="html">
        <![CDATA[
        <p>Since I've had a rejuvenation in writing again after I finally pushed this sites redesign live I have had a link component at the bottom of every article stating that I have availabilty for new client work.</p>
<p>Fast forward ~9 weeks from the website going live and 15 articles later I thought it would be neat to have a beter 'call out' at the bottom of my articles. A &quot;question and answer&quot; that could show potential cliens how I can help them. Because I have ended up, and will carry on, writing on a variety of topics I thought it would be even cooler if I had targetted &quot;Q and As&quot; depending on the topic of the article.</p>
<p>What I cam up with was 24 different questions and answers for Design Systems, CSS, Design Tokens and Front-End Development. The idea would be that every time my site gets rebuild each article page would have one of these different &quot;Q and As&quot; generated at random.</p>
<p>Using Eleventy I have distilled that code to help you add a random horror movie quote to your website pages (using Eleventy).</p>
<img alt="A purple box with text: Need to integrate design tokens into your build tools or component libraries? I'll integrate tokens into your build process and component libraries for smooth workflows. With a lighter purple button that has text of 'get in touch' to the right." src="/images/articles/QandA.png">
<h2 id="what-we'll-build" tabindex="-1">What We'll Build</h2>
<p>For this article we will build a component that:</p>
<ul>
<li>Displays a random film quote when the site is built.</li>
<li>Randomises the quote every time the site is rebuilt.</li>
<li>Uses a simple JSON file for storing quotes, making it easy to update and expand.</li>
</ul>
<h2 id="setting-up-the-quotes" tabindex="-1">Setting Up The Quotes</h2>
<p>First, we will need to create a <code>.json</code> file to store our film quotes. We can add a new file (<code>film-quotes.json</code>) in the <code>_data</code> folder of your Eleventy project and populate it with your favourite film qoutes. I'm a big horror fan, so for me it would look somehing like this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"quotes"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"They're here."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Poltergeist"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"Do you like scary movies?"</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Scream"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"Whatever you do, don’t fall asleep."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"A Nightmare on Elm Street"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"Be afraid… Be very afraid."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"The Fly"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"It’s alive! It’s alive!"</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Frankenstein"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"Here’s Johnny!"</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"The Shining"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"We all go a little mad sometimes."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Psycho"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"I see dead people."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"The Sixth Sense"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"You’re gonna need a bigger boat."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Jaws"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"In space, no one can hear you scream."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Alien"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="creating-the-randomiser" tabindex="-1">Creating The Randomiser</h2>
<p>Next, we’ll create a shortcode to fetch a random quote from our JSON file.</p>
<p>This shortcode will pick a single random quote during the build process, ensuring that the selected quote changes only when the site is rebuilt. The setup is simple, using the Math.random() function to select a quote from the list.</p>
<p>Add the following code to your .eleventy.js file:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">eleventyConfig</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Load film quotes</span>
  <span class="token keyword">const</span> filmQuotes <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./website/_data/film-quotes.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Register random film quote shortcode</span>
  config<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">'randomFilmQuote'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> randomIndex <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> randomQuote <span class="token operator">=</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">[</span>randomIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token comment">// Return the quote directly</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">
    &lt;blockquote>
      </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>randomQuote<span class="token punctuation">.</span>quote<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">
      &lt;cite>— </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>randomQuote<span class="token punctuation">.</span>film<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&lt;/cite>
    &lt;/blockquote>
    </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2 id="using-the-shortcode-in-your-template" tabindex="-1">Using The Shortcode In Your Template</h2>
<p>In your Nunjucks template (or any Eleventy compatible emplate), use the <code>randomFilmQuote</code> shortcode wherever you want the quote to appear.</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token operator">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token operator">=</span><span class="token string">"quote-of-the-day"</span><span class="token operator">></span>
  <span class="token operator">&lt;</span><span class="token variable">h2</span><span class="token operator">></span><span class="token variable">Film</span> <span class="token variable">Quote</span> <span class="token variable">of</span> <span class="token variable">the</span> <span class="token variable">Day</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">h2</span><span class="token operator">></span>
  <span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">randomFilmQuote</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">div</span><span class="token operator">></span></code></pre>
<h2 id="updating-the-randomiser-to-use-a-nunjucks-component" tabindex="-1">Updating the Randomiser to Use a Nunjucks Component</h2>
<p>I don't know about you, but I prefer to have things as 'close to the metal' as possible, so let's pull the HTML generated in the shortcode out and put it into a Nunjucks component that can be called instead.</p>
<h3 id="moving-the-html-into-a-nunjucks-component" tabindex="-1">Moving the HTML into a Nunjucks Component</h3>
<p>Create a Nunjucks component template in your project. Let’s call it <code>film-quotes.njk</code>, and place it in your components folder (<code>src/incldues/components/film[quotes.njk</code>):</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">set</span> <span class="token variable">randomQuote</span> <span class="token operator">=</span> <span class="token function">randomFilmQuote</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">%</span><span class="token punctuation">}</span>

<span class="token operator">&lt;</span><span class="token variable">blockquote</span><span class="token operator">></span>
  <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">randomQuote</span><span class="token punctuation">.</span><span class="token variable">quote</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
  <span class="token operator">&lt;</span><span class="token variable">cite</span><span class="token operator">></span>— <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">randomQuote</span><span class="token punctuation">.</span><span class="token variable">film</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">cite</span><span class="token operator">></span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">blockquote</span><span class="token operator">></span></code></pre>
<h3 id="updating-the-shortcode-to-use-the-component" tabindex="-1">Updating the Shortcode to Use The Component</h3>
<p>As we're removing the HTML from he shortcode we will need to update it so that it can render the Nunjucks component instead of directly generating the HTML. To do this, we can use Eleventy's built-in Nunucks rendering</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Load film quotes</span>
  <span class="token keyword">const</span> filmQuotes <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./website/_data/film-quotes.json'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Register random film quote shortcode</span>
  config<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">'randomFilmQuote'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> randomIndex <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">[</span>randomIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Expose the shortcode for Nunjucks</span>
  config<span class="token punctuation">.</span><span class="token function">addNunjucksGlobal</span><span class="token punctuation">(</span><span class="token string">'randomFilmQuote'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> randomIndex <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> filmQuotes<span class="token punctuation">.</span>quotes<span class="token punctuation">[</span>randomIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="updating-the-template-to-use-the-shortcode" tabindex="-1">Updating the Template to Use The Shortcode</h3>
<p>With this update to the Shortcode we don't need to make any changes to our template</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token operator">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token operator">=</span><span class="token string">"quote-of-the-day"</span><span class="token operator">></span>
  <span class="token operator">&lt;</span><span class="token variable">h2</span><span class="token operator">></span><span class="token variable">Film</span> <span class="token variable">Quote</span> <span class="token variable">of</span> <span class="token variable">the</span> <span class="token variable">Day</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">h2</span><span class="token operator">></span>
  <span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">randomFilmQuote</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">div</span><span class="token operator">></span></code></pre>
<h2 id="creating-choices-with-sets-of-quotes" tabindex="-1">Creating choices With Sets Of Quotes</h2>
<p>With my sites component I mentioned I have 4 categories that can either be chosen per page or per component instance or left to be completely random. Let's see what we need to do to that if we have quotes from horror movies and sci-fi movies.</p>
<h3 id="updating-the-.json" tabindex="-1">Updating the .json</h3>
<p>Let's split the quotes out into two categories (I've shortened the <code>.json</code> for this example):</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"horror"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"They're here."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Poltergeist"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"Do you like scary movies?"</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Scream"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token property">"scifi"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"In space, no one can hear you scream."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Alien"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span>
      <span class="token property">"quote"</span><span class="token operator">:</span> <span class="token string">"The Force will be with you. Always."</span><span class="token punctuation">,</span>
      <span class="token property">"film"</span><span class="token operator">:</span> <span class="token string">"Star Wars"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">}</span></code></pre>
<p>Now we need to add a bunch more JavaScript to our shortcode to allow for the multiple categories and the option to choose which category or not:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">config</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// Load film quotes</span>
  <span class="token keyword">const</span> filmQuotes <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>
    fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'website/_data/film-quotes.json'</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Register random film quote shortcode</span>
  config<span class="token punctuation">.</span><span class="token function">addShortcode</span><span class="token punctuation">(</span><span class="token string">'randomFilmQuote'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">category <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> selectedQuotes<span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>category<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      selectedQuotes <span class="token operator">=</span> filmQuotes<span class="token punctuation">[</span>category<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>selectedQuotes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>
          <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Category '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>category<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">' not found. Available categories: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>
            filmQuotes
          <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">', '</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token comment">// Use all quotes if no category specified</span>
      selectedQuotes <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span>filmQuotes<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">const</span> randomIndex <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> selectedQuotes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> selectedQuotes<span class="token punctuation">[</span>randomIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Expose the shortcode for Nunjucks</span>
  config<span class="token punctuation">.</span><span class="token function">addNunjucksGlobal</span><span class="token punctuation">(</span><span class="token string">'randomFilmQuote'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">category <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> selectedQuotes<span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>category<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      selectedQuotes <span class="token operator">=</span> filmQuotes<span class="token punctuation">[</span>category<span class="token punctuation">]</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>selectedQuotes<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>
          <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Category '</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>category<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">' not found. Available categories: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>
            filmQuotes
          <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">', '</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      selectedQuotes <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span>filmQuotes<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">const</span> randomIndex <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> selectedQuotes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> selectedQuotes<span class="token punctuation">[</span>randomIndex<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Now we can add an <code>if</code> statement to our nunjucks to see if there is a category in the frontmatter</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">if</span> <span class="token variable">category</span> <span class="token operator">%</span><span class="token punctuation">}</span>
  <span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">set</span> <span class="token variable">randomQuote</span> <span class="token operator">=</span> <span class="token function">randomFilmQuote</span><span class="token punctuation">(</span><span class="token variable">category</span><span class="token punctuation">)</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token keyword">else</span> <span class="token operator">%</span><span class="token punctuation">}</span>
  <span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">set</span> <span class="token variable">randomQuote</span> <span class="token operator">=</span> <span class="token function">randomFilmQuote</span><span class="token punctuation">(</span><span class="token variable">null</span><span class="token punctuation">)</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">endif</span> <span class="token operator">%</span><span class="token punctuation">}</span>

<span class="token operator">&lt;</span><span class="token variable">blockquote</span> <span class="token variable">class</span><span class="token operator">=</span><span class="token string">"film-quote"</span><span class="token operator">></span>
  <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">randomQuote</span><span class="token punctuation">.</span><span class="token variable">quote</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
  <span class="token operator">&lt;</span><span class="token variable">cite</span><span class="token operator">></span>— <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token variable">randomQuote</span><span class="token punctuation">.</span><span class="token variable">film</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">cite</span><span class="token operator">></span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">blockquote</span><span class="token operator">></span></code></pre>
<p>If we set the <code>category</code> in the frontmatter of the page it will then pick a random quote from that category</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span>
<span class="token key atrule">quoteCategory</span><span class="token punctuation">:</span> <span class="token string">'scifi'</span>
<span class="token punctuation">---</span></code></pre>
<img alt="a light orange box with a heading of Film Quote of the Day - The Force will be with you. Always. - Star Wars" src="/images/articles/FilmQuote.png">
<p>The approach we've looked at in this article could be applied to a wide variety of uses cases beyond film quotes, or questions and answers. You could use it to display a random testimonial, rotate customer feedback on your landing pages. Alternatively you could implement it to showcase random facts or trivia. Or, like I do, you could use this to power targeted calls to action, displaying relevant messages to specific blogposts.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 6) - Layers, referencing tokens in Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-6.html"/>
      <updated>2024-12-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-6.html</id>
      <content type="html">
        <![CDATA[
        <p>In previous tutorials, we explored how to create and generate design tokens using Style Dictionary. Now, we'll build upon that foundation by setting up token layers in Style Dictionary, showing how to reference tokens across layers and generate outputs for better usability.</p>
<h2 id="a-brief-explanation-of-design-tokens-layers" tabindex="-1">A brief explanation of Design Tokens layers</h2>
<p>Design Token layers can be essential for creating a scalable and maintainable design system. They can help separate raw values from their contextual meanings. In separating tokens into different layers, such as base, semantic, and component tokens, we can better organise their purposes and usage while ensuring the system remains flexible and future-proof.</p>
<p>The most common layers used for Design Tokens in a Design System include <strong>base</strong>, <strong>semantic</strong>, and <strong>component</strong> tokens, each serve a unique role in your workflow.</p>
<ul>
<li><strong>Base Tokens</strong>: These are the raw, literal values, such as <code>#bada55</code> for a green colour or <code>1rem</code> for spacing. They form the foundation of your design system, with descriptive names that reflect their physical properties (e.g., <code>color-green-400</code>, <code>spacing-small</code>).</li>
<li><strong>Semantic Tokens</strong>: These tokens provide context and meaning to the base tokens. For example, <code>--note-color</code> might reference the base token <code>--color-green-400</code>. Semantic tokens abstract intent, making them easier to use and apply consistently across a design system.</li>
<li><strong>Component Tokens</strong>: These tokens define values specific to individual components, such as <code>--button-primary-bg</code> for a button’s background colour. Component tokens build upon semantic tokens to tailor the design system for particular use cases. While they play a crucial role in token workflows, we won’t explore them in detail today, focusing instead on base and semantic layers.</li>
</ul>
<p>Separating tokens into layers provides flexibility and scalability. Semantic tokens allow users to work with meaningful names while base tokens remain stable and reusable. This separation can also support theming, where adjusting base tokens can create design variations without changes to semantic tokens.</p>
<p>While “base” and “semantic” are widely used terms, some teams prefer alternatives like “literal” or “raw” for base tokens and “contextual” for semantic tokens.</p>
<p>Regardless of your chosen terminology, maintaining clarity and consistency within your system is key.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>For more details on Design Tokens layers you can read <a href="https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676">Naming Tokens in Design Systems</a> from Nathan Curtis and <a href="https://www.smashingmagazine.com/2024/05/naming-best-practices/%22">Best Practices For Naming Design Tokens, Components And Variables</a> from Cosima on Smashing Magazine</p>
</div></div>
<h2 id="setting-up-style-dictionary-for-token-layers" tabindex="-1">Setting Up Style Dictionary for Token Layers</h2>
<p>To effectively separate token layers using Style Dictionary, we will organise our files and folders to reflect the layered structure we are aiming for. This setup allows us to maintain a clear distinction between the raw values and their contextual meanings while also enabling outputs that can meet various design and development goals.</p>
<h3 id="configuring-style-dictionary-to-separate-base-and-semantic-tokens" tabindex="-1">Configuring Style Dictionary to Separate Base and Semantic Tokens</h3>
<p>The first step to setting up token layers is to organise the token files into distinct folders for base and semantic tokens. This should make it easier to manage each layer independently.</p>
<p>Here’s an example of a simple folder structure:</p>
<pre><code>tokens/
    ├── base/
    │   ├── colors.tokens
    │   ├── spacing.tokens
    └── semantic/
        ├── colors.tokens
        ├── padding.tokens
</code></pre>
<p>To generate separate outputs for these layers, we’ll configure Style Dictionary to filter tokens by folder and output them to distinct files or directories. Below is an example configuration using Style Dictionary:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token comment">// Output file for base tokens</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'base/tokens.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token comment">// Filter for base tokens</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token comment">// Output file for semantic tokens</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'semantic/tokens.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token comment">// Filter for semantic tokens</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This configuration will build two separate outputs, one for the base tokens (<code>build/base/tokens.css</code>) and another for the semantic tokens (<code>build/semantic/tokens.css</code>).</p>
<h3 id="referencing-base-tokens-in-semantic-tokens" tabindex="-1">Referencing Base Tokens in Semantic Tokens</h3>
<p>Design Token layers can build upon other layers by referencing them in their definitions. Style Dictionary makes this simple with its {tokenPath} syntax. For example:</p>
<p><strong>Base Tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff0000"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Semantic Tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"warning"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.400}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Using the configuration above this will resolve the <code>{color-warning}</code> in the semantic tokens to a hardcoded value:</p>
<p><strong>Base Tokens CSS</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-red-400</span><span class="token punctuation">:</span> #ff0000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Semantic Tokens CSS</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-warning</span><span class="token punctuation">:</span> #ff0000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>By default, Style Dictionary replaces the <code>{color.red.400}</code> reference with its resolved value <code>(#ff0000)</code>. This behaviour is intentional and ensures the output works even if references are not supported in the target environment.</p>
<h2 id="retaining-variable-references-in-outputs" tabindex="-1">Retaining Variable References in Outputs</h2>
<p>If you want the semantic tokens to reference base tokens as CSS custom properties or Sass variables (for example), you need to enable the <code>outputReferences</code> option in your Style Dictionary configuration:</p>
<p>The updated configuration file now looks like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'base/tokens.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'base'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'semantic/tokens.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With this updated configuration, the output will retain references:</p>
<p><strong>Base Tokens CSS</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-red-400</span><span class="token punctuation">:</span> #ff0000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Semantic Tokens CSS</strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-warning</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-red-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="variable-references-vs.-hardcoded-values" tabindex="-1">Variable References vs. Hardcoded Values</h3>
<p>When generating semantic tokens, you can decide whether to reference base tokens as variables or use hard coded values:</p>
<p><strong>Variable References</strong> (<code>--warning-color: var(--color-red-400);</code> )</p>
<p>Referencing base tokens as variables ensures that updates to base tokens cascade automatically to semantic tokens. This is particularly useful for theming or maintaining consistency across large systems. However, it requires including both base and semantic tokens in the final output, which can increase file size and dependencies.</p>
<p><strong>Hardcoded Values</strong> (<code>--warning-color: #ff0000</code>)</p>
<p>Hardcoding values in semantic tokens improves portability, as semantic tokens can be used independently of base tokens. However, it sacrifices flexibility, requiring updates in multiple places if a base value changes.</p>
<p>Choosing between these approaches depends on the goals of your design system. Variable references are ideal for systems where flexibility and theming are priorities, while hardcoded values can work better in simpler setups or when portability is key.</p>
<h2 id="generating-separate-files-with-layered-outputs" tabindex="-1">Generating Separate Files with Layered Outputs</h2>
<p>To effectively manage layered Design Tokens, I think it's essential to generate separate output files that maintain the folder structure and filenames of the source tokens. This approach ensures that each file remains modular and easy to integrate into your workflows. Using Style Dictionary, we can achieve this while maintaining proper references in semantic tokens.</p>
<p>To combine the Design Token Layers with <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-5">separate file outputs from the fifth article</a> we need to change our configuration file a bit.</p>
<p>The code for this part of the series <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/06-creating-layers">can be found here</a></p>
<p>First, we're going to make use of the <code>glob</code> npm package to easily find all the <code>.tokens</code> files in the folder.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> glob</code></pre>
<p>We then need to create an array that processes each <code>.tokens</code> file to generate corresponding <code>.css</code> outputs, preserving the folder structure, filtering tokens by file, and enabling references for semantic tokens.</p>
<p>If you prefer hardcoded values and want to reduce the number of files, simply omit the <code>outputReferences</code> option from the configuration.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> globSync <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'glob'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> path <span class="token keyword">from</span> <span class="token string">'path'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> <span class="token function">globSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens/**/*.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> relativeFilePath <span class="token operator">=</span> path
          <span class="token punctuation">.</span><span class="token function">relative</span><span class="token punctuation">(</span><span class="token string">'src/tokens'</span><span class="token punctuation">,</span> file<span class="token punctuation">)</span>
          <span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\\</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> relativeFilePath<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'.tokens'</span><span class="token punctuation">,</span> <span class="token string">'.css'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
          <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span>relativeFilePath<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">outputReferences</span><span class="token operator">:</span> file<span class="token punctuation">.</span><span class="token function">includes</span><span class="token punctuation">(</span><span class="token string">'semantic'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This configuration generates <code>.css</code> files for each <code>.tokens</code> file found in the src/tokens directory, preserving the folder structure and applying specific logic for base and semantic tokens:</p>
<h3 id="directory-structure" tabindex="-1">Directory Structure</h3>
<p>For a <code>src/tokens/</code> directory structured like this:</p>
<pre><code>src/tokens/
├── base/
│   ├── color.tokens
│   ├── spacing.tokens
├── semantic/
│   ├── color.tokens
│   ├── typography.tokens
</code></pre>
<p>The output directory will look like this:</p>
<pre><code>build/css/
├── base/
│   ├── color.css
│   ├── spacing.css
├── semantic/
│   ├── color.css
│   ├── typography.css
</code></pre>
<h3 id="base-token-output" tabindex="-1">Base Token Output</h3>
<p>Tokens in base files output hard coded values without references. For example:</p>
<p><strong><code>tokens/base/color.tokens</code></strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"red"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"400"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff0000"</span><span class="token punctuation">,</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong><code>build/base/color.css</code></strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-red-400</span><span class="token punctuation">:</span> #ff0000<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="semantic-token-output" tabindex="-1">Semantic Token Output</h3>
<p>Tokens in semantic files reference base tokens using <code>var(...)</code>. For example:
<strong><code>tokens/semantic/color.tokens</code></strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"warning"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"{color.red.400}"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong><code>build/semantic/color.css</code></strong></p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-warning</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-red-400<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="a-note-on-warnings" tabindex="-1">A Note on Warnings</h3>
<p>Using this approach will likely have Style Dictionary in a bit of a spin and provide a <strong>warning</strong> in the terminal when the code is generated.</p>
<pre class="language-bash"><code class="language-bash">⚠️ build/css/semantic/padding.css
While building semantic/padding.css, filtered out token references were found<span class="token punctuation">;</span> output may be unexpected. Ignore this warning <span class="token keyword">if</span> intentional.</code></pre>
<p>The warning indicates that some tokens in the output reference other tokens that were filtered out, potentially leading to broken references in the generated file. This happens because <code>outputReferences: true</code> tries to preserve variable references (<code>var(--token-name)</code>), but the referenced tokens are not included in the same output file.</p>
<p>I think you can safely ignore the warning if you’ve confirmed that the referenced tokens are included in other output files used alongside the semantic files, and the output meets your expectations.</p>
<p>However, if the semantic files need to function independently, you should either address the warning by including all necessary references in the same file or remove outputReferences: true to default to hardcoded values.</p>
<h2 id="component-tokens" tabindex="-1">Component Tokens</h2>
<p>While this article focuses on two layers of Design Tokens, it’s worth briefly introducing <strong>component tokens</strong> as the next layer in a Design Token hierarchy. Component tokens are values tailored to specific elements and components, such as buttons, cards, or headings, and are often built upon semantic tokens to ensure consistency with the broader Design System.</p>
<p>As an example, a button's background colour might use a semantic token like <code>--primary-color</code> (if you set <code>outputPreferences: true</code> like above):</p>
<pre class="language-css"><code class="language-css"><span class="token property">--button-primary-bg</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Component tokens can provide flexibility for customisation while maintaining alignment with the Design System’s semantics. They enable teams to define granular, component-specific styles without duplicating design intent across multiple components.</p>
<p>This approach also makes it easier to manage component-level theming and variations. For instance, a <code>--button-secondary-bg</code> token could reference the same semantic base but apply a slightly different tint for differentiation.</p>
<p>We’ll explore the role of component tokens, their setup, and practical applications in a future article, where they’ll be integrated as part of a cohesive Design Tokens workflow.</p>
<p>Layering Design Tokens with Style Dictionary is a practical way to create a clear and scalable Design System. By splitting tokens into layers like base and semantic, you can define them more clearly, adapt easily for theming, and make life simpler for design and development teams.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Quick and Dirty Colour Palettes using color-mix()</title>
      <link href="https://www.alwaystwisted.com/articles/quick-and-dirty-colour-palettes-using-color-mix.html"/>
      <updated>2024-12-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/quick-and-dirty-colour-palettes-using-color-mix.html</id>
      <content type="html">
        <![CDATA[
        <p>When I first started tinkering on the idea of a redesign of this site in ~2019 (yeah, it took that long) I started prototyping the layout (which changed) and other aspects of the site (theming) using CodePen.</p>
<p>To make things easier with my idea for theming (having lighter and darker variations of the primary colour for the background, foreground, etc.) I looked at using the (then) relatively new CSS feature <code>color-mix()</code>.</p>
<h2 id="what-is-color-mix()%3F" tabindex="-1">What is color-mix()?</h2>
<p>Simply put, rhe <code>color-mix()</code> CSS function lets you blend two colours together. You also have the option to choose how much of each colour you want to mix and pick the colour space it works in, like <code>srgb</code>, or <code>display-p3</code>.</p>
<p>This makes it great for creating simple colour palettes with:</p>
<ul>
<li><strong>tints</strong>: adding a bit of white to lighten a colour.</li>
<li><strong>shades</strong>: mixing in black to darken it.</li>
<li><strong>opacity</strong>: blend a colour with the <code>transparent</code> keyword to allow the background to bleed through.</li>
</ul>
<p>The syntax for <code>color-mix</code> is quite simple:</p>
<pre class="language-css"><code class="language-css"><span class="token function">color-mix</span><span class="token punctuation">(</span>in &lt;color-space><span class="token punctuation">,</span> &lt;color-1> &lt;percentage-1><span class="token punctuation">,</span> &lt;color-2> &lt;percentage-2><span class="token punctuation">)</span></code></pre>
<p>Here's what each part means:</p>
<ol>
<li><code>&lt;color-space&gt;</code> specifies the colours space to do the blending in, common options are: <code>srgb</code> and <code>display-p3</code>.</li>
<li><code>&lt;color-1&gt;</code> is the first colour in the mix, this could be a custom property. a named colour, or a colour code.</li>
<li><code>&lt;percentage-1&gt;</code> denotes the proportion of the first colour to be blended.</li>
<li><code>&lt;color-2&gt;</code> is the second colour that is to be blended.</li>
<li><code>&lt;percentage-2&gt;</code> would be how much of the second colour is mixed with the first.</li>
</ol>
<p>You can also omit one of the percentages, the remaining percentage is automatically calculated:</p>
<pre class="language-css"><code class="language-css"><span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> #bada55 70%<span class="token punctuation">,</span> #c0ffee 30%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Can be shortened to either:</p>
<pre class="language-css"><code class="language-css"><span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> #bada55 70%<span class="token punctuation">,</span> #c0ffee<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Or:</p>
<pre class="language-css"><code class="language-css"><span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> #bada55<span class="token punctuation">,</span> #c0ffee 30%<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><a href="https://bsky.app/profile/nerdy.dev">Adam</a> explains how <code>color-mix()</code> works and more in <a href="https://developer.chrome.com/docs/css-ui/css-color-mix">this Chrome Developers blogpost</a>.</p>
</div></div>
<h2 id="creating-simple-colour-palettes" tabindex="-1">Creating Simple Colour Palettes</h2>
<p>Let's start with a primary colour and black and white as CSS custom properties and generate some tints and shades using <code>color-mix()</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-black</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
  <span class="token property">--color-white</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>

  <span class="token comment">/* tints */</span>
  <span class="token property">--color-primary--tint-10</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 10%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 20%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">/* Shades */</span>
  <span class="token property">--color-primary--shade-10</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> 10%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--shade-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> 20%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>With just a few lines, you’ve got lighter and darker variations that you can reuse for things like hover states, text, or borders.</p>
<h2 id="adding-opacity-variants" tabindex="-1">Adding Opacity Variants</h2>
<p>If you need semi-transparent colours, <code>color-mix()</code> works just as well. By blending with <code>transparent</code>, you can create a range of opacity levels:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>

  <span class="token comment">/* Opaques */</span>
  <span class="token property">--color-primary--opacity-10</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    transparent 10%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--opacity-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    transparent 20%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>These could be super handy for things like overlays, highlights, or subtle backgrounds.</p>
<h2 id="building-a-colourful-neutral-palette" tabindex="-1">Building A Colourful Neutral Palette</h2>
<p>Your neutral colours, going from white to black could look a little better if they had some of your primary colour in the mix. Using <code>color-mix()</code> makes this super easy:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-black</span><span class="token punctuation">:</span> #000000<span class="token punctuation">;</span>
  <span class="token property">--color-white</span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>

  <span class="token property">--color-primary--neutral-10</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> 10%<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span> 3%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--neutral-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> 20%<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span> 3%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This can give your neutral colour palette a softer tone that feels connected to the primary colour.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>If you define a percentage for both colours, but that percentage does not add up to 100% the remaining percentage of the colour is <code>transparent</code>.</p>
</div></div>
<h2 id="bringing-it-together" tabindex="-1">Bringing It Together</h2>
<p>So far, we've looked at creating simple tint, shade, opaque, and neutral colour palettes using the <code>color-mix()</code> function. Below is a demo of these colour palettes, include options to:</p>
<ul>
<li>change the primary colour</li>
<li>set the percentage of colour to add to the neutral palette</li>
<li>the CSS of the palettes that can be copied and pasted into your codebase.</li>
</ul>
<div class="at-g-feature">
<iframe height="600" style="width: 100%;" scrolling="no" title="Quick and Dirty Colour Palettes using color-mix()" src="https://codepen.io/sturobson/embed/preview/QwLNpgv?default-tab=result&theme-id=dark" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
  See the Pen <a href="https://codepen.io/sturobson/pen/QwLNpgv">
  Quick and Dirty Colour Palettes using color-mix()</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe>
</div>
<h2 id="creating-a-'dirty-hack'-dynamic-color-mix()" tabindex="-1">Creating a 'Dirty Hack' Dynamic color-mix()</h2>
<p>For even quicker prototyping you can create a 'dynamic' custom property that uses the <code>*</code> selector.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #BADA55<span class="token punctuation">;</span>
  <span class="token property">--color-white</span><span class="token punctuation">:</span> #FFFFFF<span class="token punctuation">;</span>
  <span class="token property">--mix-value</span><span class="token punctuation">:</span> 50%<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">*</span> <span class="token punctuation">{</span>
  <span class="token property">--color</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
 in srgb<span class="token punctuation">,</span>
 <span class="token function">var</span><span class="token punctuation">(</span>--custom-color<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
 <span class="token function">var</span><span class="token punctuation">(</span>--custom-mix-color<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--mix-value<span class="token punctuation">)</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="what%E2%80%99s-happening-here%3F" tabindex="-1">What’s Happening Here?</h3>
<ol>
<li><code>--custom-color</code>: Allows you to set a custom colour, which falls back to the <code>--primary-color</code>;</li>
<li><code>--mix-color</code>: Sets a new colour to mix which defaults to <code>--color-white</code>;</li>
<li><code>--mix-value</code>: Controls the percentage of the mix dynamically.</li>
<li><code>*</code>: Declares the calculated <code>--color</code> and makes it available to all elements</li>
</ol>
<h3 id="performance-issues-with-the-*-selector" tabindex="-1">Performance Issues with the * Selector</h3>
<p>While the <code>*</code> selector is useful for experimentation, it’s <strong>not suitable for production</strong> due to potential performance concerns:</p>
<ul>
<li><strong>Recalculation Costs</strong>: Every element on the page could recalculate the --color property whenever --value changes.</li>
<li><strong>Specificity Conflicts</strong>: The <code>*</code> selector applies styles indiscriminately, potentially overriding intended styles.</li>
</ul>
<h2 id="the-future-with-css-functions" tabindex="-1">The Future with CSS Functions</h2>
<p>Looking ahead, <a href="https://css.oddbird.net/sasslike/mixins-functions/">Functions and Mixins in CSS</a> aim to replace common preprocessing patterns by giving CSS authors the ability to define reusable logic natively.</p>
<p>These functions operate in the <strong>value space</strong> of CSS, meaning they compute and return values like colours, lengths, or strings, which can then be assigned to properties.</p>
<p>Combining the CSS <code>color-mix()</code> feature with the proposed custom function syntax could create a better way for dynamic</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--primary-color</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>
  <span class="token property">--black</span><span class="token punctuation">:</span> #000<span class="token punctuation">;</span>
  <span class="token property">--white</span><span class="token punctuation">:</span> #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@function</span> <span class="token function">--tint-shade</span><span class="token punctuation">(</span>--color<span class="token punctuation">,</span> --mix-color<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
  <span class="token property">result</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>in srgb<span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--color<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--mix-color<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.component</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">--tint-shade</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--black<span class="token punctuation">)</span> 10%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.component:hover</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> <span class="token function">--tint-shade</span><span class="token punctuation">(</span><span class="token function">var</span><span class="token punctuation">(</span>--primary-color<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">var</span><span class="token punctuation">(</span>--black<span class="token punctuation">)</span> 30%<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This CSS function takes two colours and a percentage and then returns the computed mixed colour for use anywhere it is called in the CSS.</p>
<h3 id="benefits-and-concerns-with-native-css-functions-and-mixins" tabindex="-1">Benefits and Concerns with Native CSS Functions and Mixins</h3>
<p>Native CSS functions and mixins bring some exciting possibilities. They let you skip preprocessors like Sass or PostCSS, which can simplify your workflow by reducing dependencies and build steps.</p>
<p>That said, they’re not without challenges. Performance might take a hit with complex functions that need constant recalculations, like during animations. Planning reusable functions and mixins also requires thought, especially when juggling things like fallbacks or cascading rules.</p>
<p>The W3C is currently exploring this new specification to enhance CSS’s flexibility. As this specification is still under discussion, its details may evolve, it may be some time before we can experiment and use it in production. It's exciting, none-the-less.</p>
<h2 id="using-sass-to-automate-css-custom-properties" tabindex="-1">Using Sass to Automate CSS Custom Properties</h2>
<p>Whilst we're waiting for the cool new CSS with functions and mixins, and if you're already using Sass in your code base we can make things a little easier by using Sass mixins to generate the custom properties - nobody's got time to write (almost) the same code out 10, 20, 30, 40 times.</p>
<p>Here's a little Sass mixin that will generate the CSS custom properties for tint, shade, opaque, and neutral colour palettes</p>
<p>We will use a <code>@for</code> loop to help us, in this example we're only creating a tint colour palette of CSS custom properties:</p>
<pre class="language-scss"><code class="language-scss">
<span class="token keyword">@mixin</span> <span class="token function">generate-color-variables</span><span class="token punctuation">(</span><span class="token variable">$color-name</span><span class="token punctuation">,</span> <span class="token variable">$base-color</span><span class="token punctuation">,</span> <span class="token property"><span class="token variable">$steps</span></span><span class="token punctuation">:</span> 9<span class="token punctuation">)</span> <span class="token punctuation">{</span>
 <span class="token selector">:root </span><span class="token punctuation">{</span>
  <span class="token comment">// Generate tints</span>
  <span class="token keyword">@for</span> <span class="token variable">$i</span> <span class="token keyword">from</span> 1 <span class="token keyword">through</span> <span class="token selector"><span class="token variable">$steps</span> </span><span class="token punctuation">{</span>
   --<span class="token variable">#{$color-name}</span>--tint-#<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--<span class="token variable">#{$base-color}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> #<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span>%
   <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>To make use of the Sass mixin in our code we would need to <code>@include</code> it also:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@include</span> <span class="token function">generate-color-variables</span><span class="token punctuation">(</span><span class="token string">'color-primary'</span><span class="token punctuation">,</span> <span class="token string">'color-primary'</span><span class="token punctuation">,</span> 10<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This would generate a set of CSS custom properties:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary--tint-10</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 10%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-20</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 20%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-30</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 30%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-40</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 40%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-50</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 50%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-60</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 60%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-70</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 70%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-80</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 80%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-90</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 90%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-primary--tint-100</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
    in srgb<span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> 100%
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="the-sass-mixin-in-full" tabindex="-1">The Sass Mixin in Full</h3>
<p>Here is the complete Sass mixin that would generate the four colour palettes as CSS custom properties using <code>color-mix()</code>:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Mixin to generate CSS custom properties</span>
<span class="token keyword">@mixin</span> <span class="token function">generate-color-variables</span><span class="token punctuation">(</span><span class="token variable">$color-name</span><span class="token punctuation">,</span> <span class="token variable">$base-color</span><span class="token punctuation">,</span> <span class="token property"><span class="token variable">$steps</span></span><span class="token punctuation">:</span> 9<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token selector">:root </span><span class="token punctuation">{</span>
    <span class="token comment">// Generate tints</span>
    <span class="token keyword">@for</span> <span class="token variable">$i</span> <span class="token keyword">from</span> 1 <span class="token keyword">through</span> <span class="token selector"><span class="token variable">$steps</span> </span><span class="token punctuation">{</span>
      --<span class="token variable">#{$color-name}</span>--tint-#<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
        in srgb<span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--<span class="token variable">#{$base-color}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--color-white<span class="token punctuation">)</span> #<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span>%
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// Generate shades</span>
    <span class="token keyword">@for</span> <span class="token variable">$i</span> <span class="token keyword">from</span> 1 <span class="token keyword">through</span> <span class="token selector"><span class="token variable">$steps</span> </span><span class="token punctuation">{</span>
      --<span class="token variable">#{$color-name}</span>--shade-#<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
        in srgb<span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--<span class="token variable">#{$base-color}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> #<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span>%
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// Generate opacities</span>
    <span class="token keyword">@for</span> <span class="token variable">$i</span> <span class="token keyword">from</span> 1 <span class="token keyword">through</span> <span class="token selector"><span class="token variable">$steps</span> </span><span class="token punctuation">{</span>
      --<span class="token variable">#{$color-name}</span>--transparency-#<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
        in srgb<span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--<span class="token variable">#{$base-color}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        transparent #<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span>%
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// Generate Neutral Colours</span>
    <span class="token keyword">@for</span> <span class="token variable">$i</span> <span class="token keyword">from</span> 1 <span class="token keyword">through</span> <span class="token selector"><span class="token variable">$steps</span> </span><span class="token punctuation">{</span>
      --color--neutral-#<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token function">color-mix</span><span class="token punctuation">(</span>
        in srgb<span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--color-black<span class="token punctuation">)</span> #<span class="token punctuation">{</span><span class="token variable">$i</span> <span class="token operator">*</span> 10<span class="token punctuation">}</span>%<span class="token punctuation">,</span>
        <span class="token function">var</span><span class="token punctuation">(</span>--color-primary<span class="token punctuation">)</span> <span class="token function">var</span><span class="token punctuation">(</span>--neutral-percentage<span class="token punctuation">,</span> 3%<span class="token punctuation">)</span>
      <span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<hr>
<p>I hope I have showed you how simple it can be to quickly create your own colour palettes with <code>color-mix()</code>. Whether you're prototyping or advancing the colour system within your Design System, I think this is a great CSS feature to add to your CSS toolkit.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 5) - Organising Outputs with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-5.html"/>
      <updated>2024-12-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-5.html</id>
      <content type="html">
        <![CDATA[
        <p>As a design system grows, organising design token outputs can become increasingly important. Without a clear structure, managing tokens could become unwieldy, especially when generating outputs for different platforms or tailoring outputs for specific use cases.</p>
<p>Thoughtfully structuring your token outputs into folders and files creates a scalable foundation that simplifies maintenance and improves collaboration across teams.</p>
<p>In Part 2 of this series, we explored <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-2">how to output design tokens in different formats for various platforms</a>, such as CSS for front-end developers and XML for Android. That article also introduced the idea of grouping outputs into folders to make them easier to locate and use.</p>
<p>In Part 4, we discussed <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-4">how to manipulate token key-value pairs on output to meet specific needs</a>. This included creating custom outputs where necessary and organising them for clarity and usability.</p>
<p>Now, in this fifth tutorial, we'll build on these concepts by focusing on strategies for organising token outputs in greater detail, including how to create file structures that align with your token file structure.</p>
<p>By effectively structuring your token outputs, you enhance usability for your team and future-proof your design system for growth. Let’s dive in!</p>
<h2 id="why-organise-outputs-into-folders-and-files%3F" tabindex="-1">Why Organise Outputs into Folders and Files?</h2>
<p>Organising design token outputs into structured folders and files isn’t just a matter of preference—it’s a best practice that supports scalability, usability, and maintainability. Whether you’re managing a small or large system, a clear organisation strategy ensures that your design tokens remain manageable as the system evolves.</p>
<h3 id="benefits-of-organising-outputs" tabindex="-1">Benefits of Organising Outputs</h3>
<ol>
<li><strong>Easier Maintenance</strong>
A well-organised structure makes it simpler to locate and update specific tokens.</li>
<li><strong>Separation of Concerns</strong>
By splitting tokens into logical groups—such as colours, typography, spacing, and shadows—you ensure that each file focuses on a specific aspect of the design system.</li>
<li><strong>Clarity for Teams</strong>
The separation of design token outputs into logical groups (e.g., colours, typography, spacing) naturally enhances clarity for teams.</li>
</ol>
<h3 id="challenges-of-a-monolithic-tokens-file" tabindex="-1">Challenges of a Monolithic Tokens File</h3>
<p>Starting with a single tokens file (e.g., styles.tokens) may work for small systems, but it becomes problematic as the system scales:</p>
<ul>
<li>Difficulty in Navigation: Large files are harder to read and search, especially for new contributors.</li>
<li>Unintended Changes: Centralising all tokens increases the risk of accidental updates affecting unrelated parts of the system.</li>
<li>Reduced Flexibility: A single file limits the ability to generate tailored outputs for specific contexts, such as themes or platforms.</li>
</ul>
<p>Organising tokens into smaller files and structuring outputs into folders solves these issues, enabling a scalable and efficient design system.</p>
<h2 id="implementing-organised-token-outputs-with-style-dictionary" tabindex="-1">Implementing Organised Token Outputs with Style Dictionary</h2>
<p>Now that we’ve covered the importance of organising token outputs, let’s look at how to implement these practices using Style Dictionary. With the configuration below, we can:</p>
<ul>
<li>Dynamically generate token outputs for specific platforms and formats.</li>
<li>Align the output file structure with the input token structure.</li>
<li>Use filters and transforms to tailor outputs for your design system’s needs.</li>
</ul>
<h3 id="generating-scss-files-from-tokens" tabindex="-1">Generating SCSS Files from Tokens</h3>
<p>We’ll process <code>.tokens</code> files located in <code>src/tokens/</code> to create corresponding <code>.scss</code> files in <code>build/scss/</code>. Each <code>.tokens</code> file generates its own <code>.scss</code> file, keeping outputs modular and easy to navigate.</p>
<p>You can find the complete code for this example in the <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/05-organising-outputs">GitHub repository</a>, on the scss-output-example branch.</p>
<h4 id="example-.tokens-files" tabindex="-1">Example <code>.tokens</code> files</h4>
<p>Below are some sample <code>.tokens</code> files that demonstrate how we are defining Design Tokens in the W3C <code>.tokens</code> formt</p>
<p><strong>color.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#0052cc"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff4081"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"background"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ffffff"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"text"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#333333"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"sm"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"md"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"32px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"64px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="style-dictionary-config-file" tabindex="-1">Style Dictionary Config File</h4>
<p>Here is the JavaScript for the configuration needed:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> fs <span class="token keyword">from</span> <span class="token string">'fs'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token comment">// Read all .tokens files from the 'src/tokens' directory</span>
<span class="token keyword">const</span> tokenFiles <span class="token operator">=</span> fs
  <span class="token punctuation">.</span><span class="token function">readdirSync</span><span class="token punctuation">(</span><span class="token string">'src/tokens'</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> file<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'.tokens'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>file<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/scss/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> tokenFiles<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
        <span class="token comment">// Replace '.tokens' with '.scss' for the destination</span>
        <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>file<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'.tokens'</span><span class="token punctuation">,</span> <span class="token string">'.scss'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span>
        <span class="token comment">// Match tokens by filename</span>
        <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> file <span class="token operator">===</span> token<span class="token punctuation">.</span>filePath<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'size/pxToRem'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h5 id="key-features-of-the-configuration" tabindex="-1">Key Features of the Configuration</h5>
<ol>
<li><strong>Dynamic File Handling</strong>
Reads all <code>.tokens</code> files from <code>src/tokens</code>, ensuring flexibility as new tokens are added.</li>
<li><strong>Tailored Output Structure</strong>
Each <code>.tokens</code> file generates a corresponding <code>.scss</code> file.</li>
<li><strong>Custom Filters and Transforms</strong>
Filters match tokens to their output files, and transforms (e.g., <code>pxToRem</code>) adapt token values for specific use cases.</li>
<li><strong>Scalable and Maintainable</strong>
Aligning the output file structure with the input token structure simplifies navigation and future updates.</li>
</ol>
<h4 id="example-outputs" tabindex="-1">Example Outputs</h4>
<p>The configuration generates SCSS files like these in the <code>build/scss/</code> directory:</p>
<p><strong>color.scss</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Do not edit directly, this file was auto-generated.</span>

<span class="token property"><span class="token variable">$color-primary</span></span><span class="token punctuation">:</span> #0052cc<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-secondary</span></span><span class="token punctuation">:</span> #ff4081<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-background</span></span><span class="token punctuation">:</span> #ffffff<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-text</span></span><span class="token punctuation">:</span> #333333<span class="token punctuation">;</span></code></pre>
<p><strong>spacing.scss</strong></p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Do not edit directly, this file was auto-generated.</span>

<span class="token property"><span class="token variable">$spacing-xs</span></span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-sm</span></span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-md</span></span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-lg</span></span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-xl</span></span><span class="token punctuation">:</span> 4rem<span class="token punctuation">;</span></code></pre>
<p>Organising design token outputs into folders and files is more than a best practice—it’s a cornerstone of an efficient, scalable design system. By following the workflow outlined here and leveraging tools like Style Dictionary, you can:</p>
<ul>
<li>Simplify token management across teams.</li>
<li>Ensure outputs are tailored to platform-specific needs.</li>
<li>Future-proof your design system for growth and collaboration.</li>
</ul>
<p>This approach enhances clarity and usability for your team, laying the foundation for a design system that evolves seamlessly with your organisation’s needs.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 4) - Converting Tokens with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-4.html"/>
      <updated>2024-12-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-4.html</id>
      <content type="html">
        <![CDATA[
        <p>Implementing Design Tokens can become the backbone of a consistent, scaleable Design System across your organisation and the platforms your products are on. However, different platforms have their own requirements for how names (keys) the values of Design Tokens are expressed and consumed. Whether it is <code>dp</code> for Android, points for iOS, <code>rem</code> for the web, ensuring your Design Tokens work seamlessly across platforms isn't a nice to have, it's essential. And it's possible using Style Dictionary.</p>
<p>Value conversion is the key to making this happen, it allows a single source of truth in your Design Tokens to adapt to the unique needs of each platform you work with. Whilst you might be defining your spacing tokens using pixels (<code>16px</code>), they may need to become rems (<code>1rem</code>) for your CSS, <code>16dp</code> for Android, and <code>16pt</code> for iOS. At the same time, tokens names like <code>spacing.small</code> may need to adapt to naming conventions using kebab-case (<code>--spacing-small</code>) for CSS, your team might want snake_case (<code>spacing_small</code>) for Android, and maybe the JavaScript developers are using camelCase (<code>spacingSmall</code>) throughout the rest of their project.</p>
<p>Without the ability to convert keys and values, a unified Design System could start to break down as it encounters nuances for each platform.</p>
<p>In this fourth tutorial in my Design Tokens workflow series, we will explore how we can use Style Dictionary to handle both key and value conversion, ensuring your tokens are ready for the web, Android, iOS and beyond.</p>
<p>We'll look at practical examples of converting common token types like typography, spacing and colours and dive into how transforms and custom transform groups can adapt tokens for specific needs.</p>
<h2 id="adapting-token-names-for-different-platforms" tabindex="-1">Adapting Token Names for Different Platforms</h2>
<p>Before we take a look at how Style Dictionary can helps use convert the values of our Design Tokens for specific platforms, let's take a look at the possibilities of converting the name (key) of the Design Token.</p>
<p>Out-of-the-box Style Dictionary includes a range of name transform that can convert token keys into different formats. During the build process, these transforms map your source Design Tokens (<code>spacing.small</code>) into platform appropriate naming conventions.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>Before we dive into how Style Dictionary can transform token keys and values to match the desired naming conventions and platform-specific requirements, let’s cover a quick housekeeping item. Moving forward, we’ll use the W3C Community Group’s specification for the .tokens file format to maintain consistency. We are also using version 4.x of Style Dictionary.</p>
</div></div>
<p>Here's an example of a Design Token</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"8px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Small spacing for compact padding or margins."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="built-in-name-transforms" tabindex="-1">Built-in Name Transforms</h3>
<p>Style Dictionary offers the following commonly used name transforms (there's a noticable change from <code>v3</code> to <code>v4</code> where the <code>/cti</code> has been removed – <code>name/cti/kebab</code> is now <code>name/kebab</code>):</p>
<ol>
<li><strong><code>name/kebab</code></strong> - Converts names to kebab-case, ideal for CSS variables. Example: <code>spacing.small</code> → <code>--spacing-small</code></li>
<li><strong><code>name/camel</code></strong> - Converts names to camelCase, often used in JavaScript or JSON. Example: <code>spacing.small</code> → <code>spacingSmall</code></li>
<li><strong><code>name/snake</code></strong> - Converts names to snake_case, commonly used for Android resource files. Example: <code>spacing.small</code> → <code>spacing_small</code></li>
<li><strong><code>name/pascal</code></strong> - Converts names to PascalCase, often used for constants in Swift or Objective-C. Example: <code>spacing.small</code> → <code>SpacingSmall</code></li>
</ol>
<h4 id="transforming-keys-for-css" tabindex="-1">Transforming Keys for CSS</h4>
<p>We need to register the converting of names and values as part of the specific transform group (platform (web, ios, Android, etc)).</p>
<p>Let’s say you’re generating CSS variables for your tokens and need the keys to follow kebab-case.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/kebab'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing-small</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>If a team uses camelCase in their JavaScript projects, you can switch to the <code>name/camel</code> transform:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/camelCase'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> tokens <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">spacingSmall</span><span class="token operator">:</span> <span class="token string">'8px'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="when-and-why-to-transform-keys" tabindex="-1">When and Why to Transform Keys</h3>
<p>Key conversion ensures your Design Tokens integrate seamlessly with platform-specific tools and conventions. By automating this step with Style Dictionary, you can:</p>
<ol>
<li>Eliminate manual renaming or inconsistent variable names.</li>
<li>Create outputs that align with developer expectations and team standards.</li>
<li>Simplify collaboration by generating tokens that “speak the language” of their target platform.</li>
</ol>
<h2 id="what-is-value-conversion%3F" tabindex="-1">What is value conversion?</h2>
<p>Design Tokens, at their core, is a shared language for design and development, but that shared language has to speak the specific dialect of each platform that will consume them.</p>
<p>Being able to convert the values of your Design Tokens ensures that the Design Tokens can remain universal, adapting their outputs to meet the need of those platforms and the environments they are implemented in.</p>
<h2 id="style-dictionary-transforms" tabindex="-1">Style Dictionary Transforms</h2>
<p>Transforms in Style Dictionary work by applying rules to tokens during the build process, a transform might convert font sizes from <code>px</code> to <code>rem</code> for CSS or colour from hex (<code>#ff0000</code>) to UIColor formats for iOS. These built-in transforms can ensure that your tokens are translated into the correct units, formats, and structures. Much like add a custom parer as discussed in <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-3">the third post in this series</a>, Style Dictionary allows you to create custom transforms too.</p>
<p>Style Dictionary provides a set of built-in transforms that can take care of this value conversion for the most common use cases:</p>
<ol>
<li>
<p>Dimension Transforms
These are used for spacing, sizing, and other dimensional tokens:</p>
<ul>
<li>size/pxToRem: Converts pixel values (<code>px</code>) to rem values using a base font size (default: <code>16px</code>), example: <code>16px</code> → <code>1rem</code></li>
<li>size/remToDp: Converts pixel values to density-independent pixels (<code>dp</code>) for Android, example: <code>1rem</code> → <code>16dp</code></li>
<li>size/remToPx: Converts <code>rem</code> values back to pixels (<code>px</code>) using a base font size, example: <code>1rem</code> → <code>16px</code></li>
</ul>
</li>
<li>
<p>Colour Transforms
These handle different colour formats for various platforms:</p>
</li>
</ol>
<ul>
<li>color/css: Outputs colours as rgba or hex strings depending on transparency, example: <code>#ff5733</code> → <code>rgba(255, 87, 51, 1)</code></li>
<li>color/hex8android: Outputs an 8-digit hex string for Android, with the alpha channel first, example: <code>#ff5733</code> → <code>#80ff5733</code></li>
<li>color/UIColorSwift: Converts colours into UIColor Swift class format for iOS, example: <code>#ff5733</code> → <code>UIColor(red: 1.0, green: 0.34, blue: 0.2, alpha: 1.0)</code></li>
</ul>
<ol start="3">
<li>Typography Transforms
These handle font-related tokens:</li>
</ol>
<ul>
<li>fontFamily/css: Converts font family tokens into a valid CSS string, adding quotes where necessary, example: <code>[&quot;Arial&quot;, &quot;Helvetica&quot;, &quot;sans-serif&quot;]</code> → <code>'Arial', Helvetica, sans-serif</code></li>
<li>typography/css/shorthand: Outputs a full typography shorthand for CSS, example: <code>{ fontSize: &quot;16px&quot;, fontWeight: &quot;bold&quot; }</code> → <code>bold 16px</code></li>
</ul>
<ol start="4">
<li>Timing and Animation Transforms
Used for timing, easing, and animation properties:</li>
</ol>
<ul>
<li>time/seconds: Converts milliseconds into seconds, example: <code>2000ms</code> → <code>2s</code></li>
<li>cubicBezier/css: Formats cubic bezier values for CSS, example: <code>{ x1: 0.4, y1: 0, x2: 0.2, y2: 1 }</code> → <code>cubic-bezier(0.4, 0, 0.2, 1)</code></li>
</ul>
<ol start="5">
<li>Miscellaneous Transforms
These handle other token types:</li>
</ol>
<ul>
<li>asset/url: Wraps a URL token value in a url() function for CSS, example: &quot;<a href="https://example.com/image.png">https://example.com/image.png</a>&quot; → <code>url(&quot;https://example.com/image.png&quot;)</code></li>
<li>content/quote: Wraps string content in single quotes for CSS, example: Hello → 'Hello'</li>
</ul>
<h2 id="practical-use-cases-for-value-conversion" tabindex="-1">Practical Use Cases for Value Conversion</h2>
<p>Before we take a look at how we can use Style Dictionary to transform the values of the token to the desired values that can be consumed, a brief bit of housekeeping. Moving forward we are going to use the W3C community groups specification for their <code>.tokens</code> file format. I believe this should be the way forward to keep future posts consistent. So, let's get going and transform some values.</p>
<h3 id="converting-px-to-rem-for-the-web" tabindex="-1">Converting <code>px</code> to <code>rem</code> for the Web</h3>
<p>The configuration file for Style Dictionary adds the registration of a transform group, here we are converting <code>px</code> to <code>rem</code> and making sure the generated CSS uses kebab-case.</p>
<p>An example of a spacing design tokens set:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"4px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra small spacing for minimal separations or fine-tuned padding."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"s"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"8"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Small spacing for compact padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"m"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"16px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Medium spacing for comfortable padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"l"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"24px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Large spacing for larger separations in layouts."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"32px"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra large spacing for wide separations or white space."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/kebab'</span><span class="token punctuation">,</span> <span class="token string">'size/pxToRem'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--spacing-xs</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-s</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-m</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-l</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-xl</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>To convert dimension values for other platforms Style Dictionary likes to have you use <code>rem</code> as the tokens value rather than <code>px</code> so you can make use of their built-in transforms.</p>
</div></div>
<h3 id="converting-rem-to-dp-for-android" tabindex="-1">Converting <code>rem</code> to <code>dp</code> for Android</h3>
<p>An example of a spacing design tokens set:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">".25rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra small spacing for minimal separations or fine-tuned padding."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"s"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">".5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Small spacing for compact padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"m"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Medium spacing for comfortable padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"l"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Large spacing for larger separations in layouts."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra large spacing for wide separations or white space."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Style Dictionary includes the size/remToDp (converting <code>rem</code> to <code>dp</code> a) transform as part of its built-in Android transform group, which handles converting rem values into dp for Android. Although this is automatically included, here we are being explicit about its inclusion to show how you can modify or extend this configuration if needed.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">android</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'android'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/android/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.xml'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'android/resources'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">android</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/snake'</span><span class="token punctuation">,</span> <span class="token string">'size/remToDp'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This gives us the relevant <code>xml</code> for Android.</p>
<pre class="language-xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_xs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>4.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_s<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>8.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_m<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>16.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_l<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>24.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_xl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>32.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span></code></pre>
<h3 id="converting-color-for-swift" tabindex="-1">Converting <code>color</code> for Swift</h3>
<p>Design Tokens often include colours that need to be adapted for different platforms. For example, in Swift development, colours are commonly represented using the UIColor class in Swift. Style Dictionary makes it easy to convert a colour token into this format using the color/UIColorSwift transform.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff5733"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Primary brand colour used for buttons and links."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#33c1ff"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Secondary brand colour used for accents and highlights."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"tertiary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#75ff33"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Tertiary brand colour used for backgrounds or subtle elements."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Style Dictionary includes the color/UIColorSwift transform in its built-in ios-swift group. While this transform group automatically converts hex colours into UIColor syntax, we’re explicitly defining the group to demonstrate how you could customise it if needed.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">ios</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'ios'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/ios/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.swift'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'ios-swift/class.swift'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">ios</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/pascal'</span><span class="token punctuation">,</span> <span class="token string">'color/UIColorSwift'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This gives us a relevant <code>.swift</code> file:</p>
<pre class="language-swift"><code class="language-swift"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>

<span class="token keyword">struct</span> <span class="token class-name">Colors</span> <span class="token punctuation">{</span>
    <span class="token keyword">static</span> <span class="token keyword">let</span> <span class="token class-name">Primary</span> <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.34</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">)</span>
    <span class="token keyword">static</span> <span class="token keyword">let</span> <span class="token class-name">Secondary</span> <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.76</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">)</span>
    <span class="token keyword">static</span> <span class="token keyword">let</span> <span class="token class-name">Tertiary</span> <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.46</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="why-be-explicit%3F" tabindex="-1">Why Be Explicit?</h3>
<p>While Style Dictionary provides sensible defaults with its transform groups, being explicit offers several advantages:</p>
<p>• <strong>Clarity:</strong> Teams working on your Design System will immediately understand the transforms being applied without needing to look up defaults.</p>
<p>• <strong>Flexibility:</strong> Explicitly defining the transforms makes it easier to customise them later, for example, if you add a custom transform.</p>
<p>• <strong>Documentation:</strong> For educational purposes or shared configurations, showing the transforms provides a clear example of what’s happening under the hood.</p>
<h2 id="custom-transforms" tabindex="-1">Custom Transforms</h2>
<p>Like the ability to create custom parsers for new file formats in Style Dictionary that <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-3">we discussed in part 3</a> we also have the ability to create custom transforms for names (keys) and values of the Design Tokens.</p>
<p>Let's say we want to use the new <code>color()</code> possibilites of CSS and use <code>color(display-p3)</code> for the websites our Design System supports? We can do this with a custom transform.</p>
<p>First we would need to install a package that would help calculate the values to convert our hex colour code into <code>display-p3</code>. We can use <code>chroma-js</code> for this</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> chroma-js</code></pre>
<p>Then we need to create a new transform in our Style Dictionary config file:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// Ensure chroma-js is installed in your project</span>
<span class="token keyword">const</span> chroma <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'chroma-js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerTransform</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token comment">// Unique name for the transform</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'color/hexToDisplayP3'</span><span class="token punctuation">,</span>

  <span class="token comment">// This transform modifies the token's value</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'value'</span><span class="token punctuation">,</span>

  <span class="token comment">// Applies only to tokens of type "color"</span>
  <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>$type <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">,</span>

  <span class="token comment">// Convert hex to RGB and format as display-p3</span>
  <span class="token function-variable function">transformer</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> rgb <span class="token operator">=</span> <span class="token function">chroma</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>$value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">rgb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">color(display-p3 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now, we need to register a new transform group under the hooks.transformGroups property. This allows you to include your custom transform alongside other built-in transforms for a specific platform:</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'./tokens/*.tokens.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'web-p3'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/web/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
        <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens.css'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span>
      <span class="token punctuation">}</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/kebab'</span><span class="token punctuation">,</span> <span class="token string">'color/hexToDisplayP3'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This would give us a CSS file containing:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 1 0.341176 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-secondary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 0.2 0.756862 1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-tertiary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 0.458824 1 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>Let's wrap the code we have looked at into a single configuration file, again <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/04-converting-tokens">the code for this post in the series is available on Github</a>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> chroma <span class="token keyword">from</span> <span class="token string">'chroma-js'</span><span class="token punctuation">;</span>

<span class="token comment">// Register additional transforms</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerTransform</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'color/hexToDisplayP3'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'value'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">filter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> token<span class="token punctuation">.</span>$type <span class="token operator">===</span> <span class="token string">'color'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">transform</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> rgb <span class="token operator">=</span> <span class="token function">chroma</span><span class="token punctuation">(</span>token<span class="token punctuation">.</span>$value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">rgb</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Possible issue here</span>
    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">color(display-p3 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rgb<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span> <span class="token operator">/</span> <span class="token number">255</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">android</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'android'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/android/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.xml'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'android/resources'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">ios</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'ios-swift'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/ios/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.swift'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'ios-swift/class.swift'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token literal-property property">hooks</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">transformGroups</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'attribute/cti'</span><span class="token punctuation">,</span> <span class="token string">'name/kebab'</span><span class="token punctuation">,</span> <span class="token string">'color/hexToDisplayP3'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token literal-property property">android</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token string">'attribute/cti'</span><span class="token punctuation">,</span>
        <span class="token string">'name/snake'</span><span class="token punctuation">,</span>
        <span class="token string">'size/remToSp'</span><span class="token punctuation">,</span>
        <span class="token string">'color/hex8android'</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
      <span class="token literal-property property">ios</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token string">'attribute/cti'</span><span class="token punctuation">,</span>
        <span class="token string">'name/pascal'</span><span class="token punctuation">,</span>
        <span class="token string">'size/swift/remToCGFloat'</span><span class="token punctuation">,</span>
        <span class="token string">'color/UIColorSwift'</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Build completed!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here we have:</p>
<ul>
<li>added the custom transform to convert hex colours into the <code>color(display-p3)</code> syntax.</li>
<li>used <code>src/tokens/**/*.tokens</code> to look through any folders within <code>src/tokens/</code> and find any files ending in <code>.tokens</code>.</li>
<li>provided the platforms for css, android, and swift (iOS), defined their transform group, where the built files should live, their filename, and what file format they should be in</li>
<li>Been explicit in defining the transforms used for each platforms transform group.</li>
</ul>
<p>Taking these two <code>.tokens</code> file examples:</p>
<p><strong>/tokens/color.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#ff5733"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Primary brand colour used for buttons and links."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#33c1ff"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Secondary brand colour used for accents and highlights."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"tertiary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#75ff33"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Tertiary brand colour used for backgrounds or subtle elements."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>/tokens/spacing.tokens</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"xs"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">".25rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra small spacing for minimal separations or fine-tuned padding."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"s"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">".5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Small spacing for compact padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"m"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Medium spacing for comfortable padding or margins."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"l"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.5rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Large spacing for larger separations in layouts."</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"xl"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"2rem"</span><span class="token punctuation">,</span>
      <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span><span class="token punctuation">,</span>
      <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"Extra large spacing for wide separations or white space."</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>We get these outputs:</p>
<p><strong>/build/android/all.xml</strong></p>
<pre class="language-xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span>

<span class="token comment">&lt;!--
Do not edit directly, this file was auto-generated.
--></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>resources</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>color</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color_primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>#ffff5733<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>color</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>color</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color_secondary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>#ff33c1ff<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>color</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>color</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color_tertiary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>#ff75ff33<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>color</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_xs<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>4.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_s<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>8.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_m<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>16.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_l<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>24.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_xl<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>32.00dp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>resources</span><span class="token punctuation">></span></span></code></pre>
<p><strong>/build/ios/all.swift</strong></p>
<pre class="language-swift"><code class="language-swift"><span class="token comment">//</span>
<span class="token comment">// all.swift</span>
<span class="token comment">//</span>

<span class="token comment">// Do not edit directly, this file was auto-generated.</span>

<span class="token keyword">import</span> <span class="token class-name">UIKit</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> colorPrimary <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">1.000</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.341</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">0.200</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> colorSecondary <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.200</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.757</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">1.000</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> colorTertiary <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.459</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">1.000</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">0.200</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingL <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">24.00</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingM <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">16.00</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingS <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">8.00</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingXl <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">32.00</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingXs <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">4.00</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>/build/css/all.css</strong></p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 1 0.3411764705882353 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-secondary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 0.2 0.7568627450980392 1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--color-tertiary</span><span class="token punctuation">:</span> <span class="token function">color</span><span class="token punctuation">(</span>display-p3 0.4588235294117647 1 0.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">--spacing-xs</span><span class="token punctuation">:</span> 0.25rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-s</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-m</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-l</span><span class="token punctuation">:</span> 1.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-xl</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Adapting Design Token names (keys) and values is essential for creating a scalable and maintainable Design System. These practices ensure that your tokens align with the specific needs of each team and platform while maintaining consistency across your Design System. By providing platform-specific outputs, developers can seamlessly integrate tokens into their workflows, fostering better collaboration across teams.</p>
<p>Hopefully, this article has clarified how to adapt Design Tokens effectively for different platforms. By utilising transforms and transform groups in Style Dictionary, you can ensure your Design System remains consistent and scalable while meeting the unique requirements of every platform your team supports.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The Faculty Of Design Systems</title>
      <link href="https://www.alwaystwisted.com/articles/the-faculty-of-design-systems.html"/>
      <updated>2024-12-02T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-faculty-of-design-systems.html</id>
      <content type="html">
        <![CDATA[
        <p>I reached my late teenage years at almost the perfect time for a horror fan. The late 1990s saw a resurgence of the genre in the film industry. Sparked by the success of <em>Scream</em> in 1996, Dimension Films went through every drawer of its writer, Kevin Williamson, to see what other delights he’d written.</p>
<p>In 1997, <em>I Know What You Did Last Summer</em> was released, and in 1998, Williamson’s cross-genre <em>The Faculty</em> brought science fiction and horror to a small town in Ohio.</p>
<p>Much like Dawson and Joey discussing the best Spielberg films in <em>Dawson’s Creek</em> (another Williamson creation), these movies were packed with references to older films in their respective genres. They didn’t just tell their own stories, they built on the cultural DNA of what came before, remixing familiar tropes in clever and unexpected ways.</p>
<p>It’s fitting, then, that one of my favourite lines from <em>The Faculty</em> has stuck with me:</p>
<blockquote>
If you were going to take over the world, would you blow up the White House *Independence Day* style, or sneak in through the back door?
<cite>Casey Connor (The Faculty, 1998)</cite>
</blockquote>
<p>This question isn’t just about alien invasions, it’s a perfect metaphor for introducing something new, like a Design System, into a complex organisation.</p>
<p>Do you go in with fireworks and a grand unveiling, or do you quietly work your way into the structure until it becomes part of the system’s DNA?</p>
<h2 id="invasion-of-the-design-system" tabindex="-1">Invasion of the Design System</h2>
<p>Like a subtle sci-fi horror movie, building a Design System doesn’t have to involve loud bangs and big drama. Sometimes, it’s about quietly embedding it into existing workflows and teams until it becomes an essential part of how your organisation works.</p>
<p>Your Design System doesn’t need to arrive in a spaceship over the White House to make an impact. Instead, think of it like the creeping unease of <em>Invasion of the Body Snatchers</em>, quietly infiltrating workflows and processes until it’s simply part of the organisation’s DNA.</p>
<p>When a system is gradually built, integrated into workflows, and consistently demonstrates its value, it has the power to become indispensable. It’s like a well-executed plot twist: surprising when revealed, yet inevitable in hindsight.</p>
<p>This method can be particularly effective when resources are scarce, or when approval for a formal Design System isn’t yet on the table. Start small: address a persistent inconsistency, introduce a handful of design tokens, or offer a reusable component that saves a team time. Each small improvement fosters trust, demonstrates value, and lays the groundwork for broader adoption.</p>
<p>Like the best slow-burn horror films, this approach leaves a lasting impression. A Design System developed this way isn’t just a tool—it becomes part of the culture, shaping how teams think, work, and collaborate.</p>
<h2 id="the-big-explosion-vs.-the-quiet-revolution" tabindex="-1">The Big Explosion vs. The Quiet Revolution</h2>
<p>You could launch your Design System with fireworks, a grand unveiling like the <em>Independence Day</em> mothership making its dramatic entrance. But while a big, bold debut gets attention, it can also create chaos.</p>
<p>The reality is that a “big bang” approach can cause as many problems as it solves. It risks alienating the very people you need to win over. This is where the <em>quiet revolution</em> comes in—slowly integrating the system into workflows, proving its value piece by piece, and growing adoption naturally over time.</p>
<h3 id="the-risks-of-the-big-bang-approach" tabindex="-1">The Risks of the Big Bang Approach</h3>
<p>The “big bang” might sound appealing, but it can backfire:</p>
<ul>
<li><strong>“We don’t have time to use this.”</strong> - Teams drowning in deliverables might feel the system is an added burden.</li>
<li><strong>“Why weren’t we consulted?”</strong> - A top-down approach can alienate teams who feel excluded.</li>
<li><strong>“We already have our own components.”</strong> - Teams may view the system as redundant or even a threat.</li>
<li><strong>“Why is this being driven by that team?”</strong> - Questions about ownership can undermine trust.</li>
</ul>
<p>Big explosions might grab attention, but they often fizzle out when enthusiasm fades or resistance builds. The initial buzz doesn’t guarantee lasting adoption.</p>
<h3 id="why-a-quiet-revolution-can-work" tabindex="-1">Why a Quiet Revolution can work</h3>
<p>The quiet revolution is about creating change subtly, like the creeping takeover in <em>Invasion of the Body Snatchers</em>. By solving immediate pain points and offering tangible benefits, you build trust and adoption naturally.</p>
<ul>
<li><strong>Start small</strong> - Introduce a reusable component or a few design tokens that make work easier.</li>
<li><strong>Listen and adapt</strong> - Engage with teams to understand their challenges and incorporate their feedback.</li>
<li><strong>Be visible, but not intrusive</strong> - Show you’re there to help without forcing adoption.</li>
</ul>
<p>Over time, these small wins add up, creating a network of advocates who spread the system organically. By the time the system is fully adopted, it will feel like it was always meant to be there—an integral part of how your organisation works.</p>
<h2 id="small-team%2C-big-impact" tabindex="-1">Small Team, Big Impact</h2>
<p>Many Design Systems don’t begin with fanfare but with a handful of dedicated individuals—designers, developers, or both—quietly working behind the scenes. They’re like the small group of survivors in a horror movie, spotting the patterns others miss and taking action before it’s too late.</p>
<p>A grassroots approach often starts with small, practical observations:</p>
<ul>
<li>Multiple teams solving the same problems in slightly different ways.</li>
<li>Buttons that look similar but behave inconsistently.</li>
<li>Spacing that’s inconsistent between screens.</li>
<li>Colours that fail accessibility standards.</li>
</ul>
<p>These individuals think, <em>&quot;What if we standardise this?&quot;</em> And with that, the seeds of a Design System are planted.</p>
<h3 id="success-through-subtlety" tabindex="-1">Success Through Subtlety</h3>
<p>Small teams have the advantage of working under the radar, avoiding the pressure of delivering a fully-formed system from day one. Instead, they focus on incremental improvements, such as:</p>
<ul>
<li><strong>Streamlining repetitive work</strong> - A shared button or token set that saves time.</li>
<li><strong>Improving quality</strong> - Standardising patterns to reduce bugs and ensure accessibility compliance.</li>
<li><strong>Building trust</strong> - Demonstrating the benefits of consistency through visible, small wins.</li>
</ul>
<p>Over time, these efforts create momentum. The Design System becomes less about imposing change and more about solving shared problems. As teams experience its benefits, they naturally adopt it—and even advocate for it.</p>
<h2 id="incremental-buy-in%3A-one-step-at-a-time" tabindex="-1">Incremental Buy-in: One Step at a Time</h2>
<p>Invasion isn’t about force; it’s about persistence. Securing buy-in for a Design System works the same way—through small, meaningful steps that show value without overwhelming anyone.</p>
<p>Rolling out the system incrementally—one component, one team at a time—reduces resistance. Start with something manageable: a shared button component, a small set of tokens, or a consistent typography scale. These changes demonstrate immediate value, building trust and encouraging further adoption.</p>
<h3 id="creating-a-network-of-champions" tabindex="-1">Creating a Network of Champions</h3>
<p>When teams see tangible benefits, they become advocates. A developer might share how a component saved hours of work, or a designer might explain how tokens improved consistency. These champions spread enthusiasm, making adoption feel natural and organic.</p>
<h3 id="from-steps-to-a-movement" tabindex="-1">From Steps to a Movement</h3>
<p>Incremental improvements grow over time, turning the Design System into something larger—a movement. By the time the system is fully integrated, it won’t feel like an external addition but a natural extension of how the organisation operates.</p>
<h2 id="communicate-first%2C-build-second" tabindex="-1">Communicate First, Build Second</h2>
<p>A quiet revolution thrives on communication. Without clear dialogue, even the best-crafted system risks being misunderstood or ignored. Start with the <em>why?</em> Why does the system exist? What problems does it solve? When teams understand its value, they’re more likely to engage and advocate for it.</p>
<p>Communication isn’t just about delivering a message; it’s about fostering collaboration. By gathering feedback and involving teams in the process, the system becomes a shared effort rather than a top-down directive. Like the subtle infiltration in <em>Invasion of the Body Snatchers</em>, effective communication quietly plants the system’s seeds, helping it take root and grow naturally within the organisation.</p>
<h2 id="design-systems-as-culture%3A-a-movement%2C-not-a-mandate" tabindex="-1">Design Systems as Culture: A Movement, Not a Mandate</h2>
<p>Much like <em>Invasion of the Body Snatchers</em>, a Design System’s success lies in its gradual and understated integration. Over time, it reshapes how people think, work, and collaborate until it becomes an inseparable part of the organisation’s DNA—something so ingrained that no one remembers a time without it.</p>
<p>By the time the system is fully adopted, it won’t feel like a revolution—it’ll feel like the way things have always been done. And like the best slow-burn stories, its impact will be enduring, shaping how the organisation evolves and grows for years to come.</p>
<p>By the time anyone notices, it’s already everywhere.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Capturing URLs to Obsidian with a Bookmarklet</title>
      <link href="https://www.alwaystwisted.com/articles/capturing-urls-to-obsidian-with-a-bookmarklet.html"/>
      <updated>2024-11-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/capturing-urls-to-obsidian-with-a-bookmarklet.html</id>
      <content type="html">
        <![CDATA[
        <p>Many of us come across interesting articles, tools, or resources online and wish to save them for later reference. Over the last couple of years I've tried using an application to keep all of my 'notes' in one place and recently moved to Obsidian.</p>
<p>I wanted a bookmarklet that would help me save interesting web pages to my Obsidian Vault so I can access it at a later date. I could use the browsers native bookmarking tools but I'm often across browsers throughout my working day. I could use available third-party tools - but I want to try to keep 'everything' in markdown, in Obsidian. This article you're reading now started off in Obsidian.</p>
<p>In this post, I’ll walk you through the bookmarklet, how it works, and how you can use it to streamline your bookmarking workflow.</p>
<h2 id="what-the-bookmarklet-does" tabindex="-1">What the Bookmarklet Does</h2>
<p>This bookmarklet allows you to:</p>
<ul>
<li>Capture the current webpage title and URL.</li>
<li>Optionally modify the title.</li>
<li>Add tags for easier categorisation.</li>
<li>Extract metadata like descriptions, images, and publication dates when available.</li>
<li>Save all this information directly into your specified folder in your Obsidian vault.</li>
</ul>
<h2 id="the-full-code" tabindex="-1">The full code</h2>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">javascript</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> vault <span class="token operator">=</span> <span class="token string">'everything'</span><span class="token punctuation">;</span> <span class="token comment">// Your Obsidian vault name</span>
  <span class="token keyword">const</span> folder <span class="token operator">=</span> <span class="token string">'bookmarks'</span><span class="token punctuation">;</span> <span class="token comment">// Folder for all bookmarks</span>
  <span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">'Want to change the title?'</span><span class="token punctuation">,</span> document<span class="token punctuation">.</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> askForTags <span class="token operator">=</span> <span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">'Enter any tags, comma separated'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> tags <span class="token operator">=</span> askForTags <span class="token operator">?</span> askForTags<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

  <span class="token comment">// Function to format tags: remove spaces, replace with hyphens, add #</span>
  <span class="token keyword">function</span> <span class="token function">formatHashtags</span><span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> arr<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token string">'#'</span> <span class="token operator">+</span> str<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\s+</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  tags <span class="token operator">=</span> <span class="token function">formatHashtags</span><span class="token punctuation">(</span>tags<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> url <span class="token operator">=</span> document<span class="token punctuation">.</span>location<span class="token punctuation">.</span>href<span class="token punctuation">;</span>

  <span class="token comment">// Try to grab meta description or OG description</span>
  <span class="token keyword">let</span> description <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> metaDescription <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="description"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> ogDescription <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>
    <span class="token string">'meta[property="og:description"]'</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>metaDescription<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    description <span class="token operator">=</span> metaDescription<span class="token punctuation">.</span>content<span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ogDescription<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    description <span class="token operator">=</span> ogDescription<span class="token punctuation">.</span>content<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Try to grab OG image, Twitter image, or other social image</span>
  <span class="token keyword">let</span> imageUrl <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> ogImage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[property="og:image"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> twitterImage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="twitter:image"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>ogImage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    imageUrl <span class="token operator">=</span> ogImage<span class="token punctuation">.</span>content<span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>twitterImage<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    imageUrl <span class="token operator">=</span> twitterImage<span class="token punctuation">.</span>content<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Try to grab article:published_time</span>
  <span class="token keyword">let</span> publishedDate <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> publishedTime <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>
    <span class="token string">'meta[property="article:published_time"]'</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>publishedTime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> pubDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>publishedTime<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> pubDay <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span>pubDate<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">padStart</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> pubMonth <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span>pubDate<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">padStart</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Months are zero-indexed</span>
    <span class="token keyword">const</span> pubYear <span class="token operator">=</span> pubDate<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    publishedDate <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Published on </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>pubDay<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>pubMonth<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>pubYear<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token comment">// Format as DD-MM-YYYY</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Sanitise title to remove invalid filename characters</span>
  title <span class="token operator">=</span> title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[\\/:*?"&lt;>|]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Generate DD-MM-YYYY timestamp format</span>
  <span class="token keyword">const</span> now <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> day <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span>now<span class="token punctuation">.</span><span class="token function">getDate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">padStart</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> month <span class="token operator">=</span> <span class="token function">String</span><span class="token punctuation">(</span>now<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">padStart</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Months are zero-indexed</span>
  <span class="token keyword">const</span> year <span class="token operator">=</span> now<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> formattedDate <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>day<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>month<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>year<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token comment">// DD-MM-YYYY format</span>

  <span class="token keyword">const</span> fileName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>folder<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token comment">// Unique file name</span>

  <span class="token comment">// Format content with title, date, image, description, URL, and tags</span>
  <span class="token keyword">const</span> imageMarkdown <span class="token operator">=</span> imageUrl <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">![Image](</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)\n\n</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token comment">// Add markdown image if URL exists</span>
  <span class="token keyword">const</span> content <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>publishedDate<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">Saved on </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formattedDate<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageMarkdown<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> description <span class="token operator">+</span> <span class="token string">'\n\n'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">- [Visit the page](</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)\n\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tags<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>

  document<span class="token punctuation">.</span>location<span class="token punctuation">.</span>href <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">obsidian://new?file=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;content=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;vault=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>vault<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="breaking-down-the-code" tabindex="-1">Breaking Down the Code</h2>
<p>The bookmarklet uses JavaScript to gather data from the current webpage and construct a new note in your Obsidian vault. Let’s break it into steps.</p>
<h3 id="setting-up-the-vault-and-folder" tabindex="-1">Setting Up the Vault and Folder</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> vault <span class="token operator">=</span> <span class="token string">'everything'</span><span class="token punctuation">;</span> <span class="token comment">// Your Obsidian vault name</span>
<span class="token keyword">const</span> folder <span class="token operator">=</span> <span class="token string">'bookmarks'</span><span class="token punctuation">;</span> <span class="token comment">// Folder for bookmarks in your vault</span></code></pre>
<p>These constants define where the captured notes will be stored. Replace <code>everything</code> and <code>bookmarks</code> with the name of your vault and the desired folder path.</p>
<h3 id="prompting-for-the-title-and-tags" tabindex="-1">Prompting for the Title and Tags</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">'Want to change the title?'</span><span class="token punctuation">,</span> document<span class="token punctuation">.</span>title<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> askForTags <span class="token operator">=</span> <span class="token function">prompt</span><span class="token punctuation">(</span><span class="token string">'Enter any tags, comma separated'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> tags <span class="token operator">=</span> askForTags <span class="token operator">?</span> askForTags<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p><strong>Title:</strong> The script captures the webpage’s title (document.title) and gives you the option to modify it via a prompt.
<strong>Tags:</strong> You can enter tags separated by commas to categorise the bookmark. If you skip this, the tags will remain empty.</p>
<h3 id="formatting-tags" tabindex="-1">Formatting Tags</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">formatHashtags</span><span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> arr<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token string">'#'</span> <span class="token operator">+</span> str<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\s+</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
tags <span class="token operator">=</span> <span class="token function">formatHashtags</span><span class="token punctuation">(</span>tags<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This function:</p>
<ul>
<li>Trims whitespace from each tag.</li>
<li>Replaces spaces with hyphens to make tags URL-friendly.</li>
<li>Prepends a # to each tag, turning them into Obsidian-compatible hashtags.</li>
</ul>
<h3 id="extracting-metadata" tabindex="-1">Extracting Metadata</h3>
<h4 id="description" tabindex="-1">Description</h4>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> metaDescription <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="description"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> ogDescription <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[property="og:description"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> description <span class="token operator">=</span> metaDescription
  <span class="token operator">?</span> metaDescription<span class="token punctuation">.</span>content
  <span class="token operator">:</span> ogDescription
    <span class="token operator">?</span> ogDescription<span class="token punctuation">.</span>content
    <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span></code></pre>
<p>This retrieves the webpage’s description from <meta> tags.</p>
<h4 id="image" tabindex="-1">Image</h4>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> ogImage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[property="og:image"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> twitterImage <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'meta[name="twitter:image"]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> imageUrl <span class="token operator">=</span> ogImage
  <span class="token operator">?</span> ogImage<span class="token punctuation">.</span>content
  <span class="token operator">:</span> twitterImage
    <span class="token operator">?</span> twitterImage<span class="token punctuation">.</span>content
    <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span></code></pre>
<p>The script looks for Open Graph or Twitter image metadata to include a thumbnail.</p>
<h4 id="published-date" tabindex="-1">Published Date</h4>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> publishedTime <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>
  <span class="token string">'meta[property="article:published_time"]'</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> publishedDate <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>publishedTime<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> pubDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>publishedTime<span class="token punctuation">.</span>content<span class="token punctuation">)</span><span class="token punctuation">;</span>
  publishedDate <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Published on </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>pubDate<span class="token punctuation">.</span><span class="token function">toLocaleDateString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>It checks for the publication date in the <meta> tags and formats it.</p>
<h3 id="sanitising-the-title" tabindex="-1">Sanitising the Title</h3>
<pre class="language-javascript"><code class="language-javascript">title <span class="token operator">=</span> title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[\\/:*?"&lt;>|]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This step ensures the title is valid for file names by removing characters that might cause issues.</p>
<h3 id="constructing-the-note" tabindex="-1">Constructing the Note</h3>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> imageMarkdown <span class="token operator">=</span> imageUrl <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">![Image](</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)\n\n</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> content <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>publishedDate<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">Saved on </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>formattedDate<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageMarkdown<span class="token interpolation-punctuation punctuation">}</span></span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>description <span class="token operator">?</span> description <span class="token operator">+</span> <span class="token string">'\n\n'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">- [Visit the page](</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)\n\n</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tags<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">\n</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
<p>The script then formats the note with the collected data:</p>
<ul>
<li>Includes metadata (date, description, and image).</li>
<li>Appends the URL.</li>
<li>Adds any tags you’ve entered.</li>
</ul>
<h3 id="sending-the-note-to-obsidian" tabindex="-1">Sending the Note to Obsidian</h3>
<pre class="language-javascript"><code class="language-javascript">document<span class="token punctuation">.</span>location<span class="token punctuation">.</span>href <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">obsidian://new?file=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;content=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>content<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&amp;vault=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>vault<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
<p>Finally, the script redirects you to Obsidian’s URI scheme to create the note. This sends the note to the specified folder in your vault using Obsidian’s <code>obsidian://</code> protocol.</p>
<h2 id="how-to-use-the-bookmarklet" tabindex="-1">How to Use the Bookmarklet</h2>
<ul>
<li>Customise It:
<ul>
<li>Copy the full JavaScript code.</li>
<li>Edit the vault and folder variables to match your Obsidian setup.</li>
</ul>
</li>
<li>Create the Bookmarklet:
<ul>
<li>Create a new bookmark in Safari and paste the code into the URL field.</li>
</ul>
</li>
<li>Use It:
<ul>
<li>While browsing, click the bookmarklet.</li>
<li>Enter a title and tags (optional).</li>
<li>The note will appear in your Obsidian vault.</li>
</ul>
</li>
</ul>
<p>These steps should work in all modern browsers, I've only used this in Safari.</p>
<h2 id="hot-linking" tabindex="-1">Hot Linking</h2>
<p>When you save a url as a bookmark in Obsidian the image that is save d is the url, we are hot-linking to someone else's resource on their server. That's not nice, so I created a node script that would</p>
<ul>
<li>look into the bookmarks folder</li>
<li>find the image url in a markdown file</li>
<li>download the image to an <code>assets</code> folder in my vault</li>
<li>replace the hot link with the local link</li>
</ul>
<p>Here's the script:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> axios <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'axios'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> obsidianVaultPath <span class="token operator">=</span> <span class="token string">'/your/path/to/your/obsidian/vault'</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> bookmarksFolderPath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>
  obsidianVaultPath<span class="token punctuation">,</span>
  <span class="token string">'your/bookmark/folder'</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> imageSavePath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>bookmarksFolderPath<span class="token punctuation">,</span> <span class="token string">'your/images/folder'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>fs<span class="token punctuation">.</span><span class="token function">existsSync</span><span class="token punctuation">(</span>imageSavePath<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  fs<span class="token punctuation">.</span><span class="token function">mkdirSync</span><span class="token punctuation">(</span>imageSavePath<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">recursive</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Download the image and save it locally</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">downloadImage</span><span class="token punctuation">(</span><span class="token parameter">imageUrl<span class="token punctuation">,</span> saveFolder</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>imageUrl<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">responseType</span><span class="token operator">:</span> <span class="token string">'arraybuffer'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>response<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> imageFilename <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>saveFolder<span class="token punctuation">,</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>imageUrl<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>imageFilename<span class="token punctuation">,</span> response<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Image downloaded and saved as: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageFilename<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> imageFilename<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error downloading image:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// Process a note</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">processNote</span><span class="token punctuation">(</span><span class="token parameter">noteFilePath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> noteContent <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>noteFilePath<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> imageRegex <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">!\[\]\((http[s]?:\/\/[^\)]+)\)</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> matches <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>noteContent<span class="token punctuation">.</span><span class="token function">matchAll</span><span class="token punctuation">(</span>imageRegex<span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>matches<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> match <span class="token keyword">of</span> matches<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> imageUrl <span class="token operator">=</span> match<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Found image URL: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>imageUrl<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> localImagePath <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">downloadImage</span><span class="token punctuation">(</span>imageUrl<span class="token punctuation">,</span> imageSavePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>localImagePath<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">const</span> localImageFilename <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">basename</span><span class="token punctuation">(</span>localImagePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
          noteContent <span class="token operator">=</span> noteContent<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span>
            imageUrl<span class="token punctuation">,</span>
            <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">../assets/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>localImageFilename<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
          <span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
      fs<span class="token punctuation">.</span><span class="token function">writeFileSync</span><span class="token punctuation">(</span>noteFilePath<span class="token punctuation">,</span> noteContent<span class="token punctuation">,</span> <span class="token string">'utf-8'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Note updated: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>noteFilePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">No image URLs found in: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>noteFilePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error processing note: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>noteFilePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// Process all markdown files in the bookmarks folder</span>
<span class="token keyword">function</span> <span class="token function">processAllNotes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">try</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> files <span class="token operator">=</span> fs<span class="token punctuation">.</span><span class="token function">readdirSync</span><span class="token punctuation">(</span>bookmarksFolderPath<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> mdFiles <span class="token operator">=</span> files<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> file<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">'.md'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    mdFiles<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">file</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> noteFilePath <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>bookmarksFolderPath<span class="token punctuation">,</span> file<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">processNote</span><span class="token punctuation">(</span>noteFilePath<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Error processing files:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token function">processAllNotes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You will need to update the <code>obsidianVaultPath</code> and <code>bookmarksFolderPath</code> and also install axios (<code>npm install axios</code>).</p>
<p>There's a few issues with this script that I want to address -- sometimes the OG image is not a png, it seems Obisdian doesn't support something like WebP. If the image returned isn't recognised you would get the text of the file (better than hot-linking in my opinion).</p>
<p>In the future, I plan to share this on GitHub to make it easier for others to explore and contribute. I might even refine it further, like converting all images to PNG for consistency.</p>
<p>Initially, I considered adding a ‘to be sorted’ folder to organise bookmarks, but I realised tags provide an equally efficient solution.</p>
<p>I hope this inspires you to craft a bookmarking system that fits your workflow, especially if you’re using Obsidian.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 3) - Beyond JSON: Exploring File Formats for Design Tokens</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-3.html"/>
      <updated>2024-11-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-3.html</id>
      <content type="html">
        <![CDATA[
        <p>Before we go further into the tutorial series I thought we should take a look at the file formats you can use to generate your Design Tokens into the file outputs you need.</p>
<p>The code for this part of the series <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/03-beyond-json">available to look at on Github</a>.</p>
<p>While <code>.json</code> is the most common and natively supported format in Style Dictionary, it’s not the only option. When working with design tokens, choosing the right file format is crucial for readability, maintainability, and collaboration.</p>
<p>While <code>.json</code> is a great starting point for defining design tokens, it’s not always the most human-readable or flexible option, especially for larger or more complex token files. Custom parsers bridge this gap by enabling Style Dictionary to interpret other formats like <code>.yaml</code>, <code>.hjson</code>, <code>.json5</code>, and the <a href="https://www.designtokens.org">Design Tokens Working Group</a> formats <code>.tokens</code> and <code>.tokens.json</code>, giving you the freedom to choose what format best suits your team’s needs.</p>
<h2 id="let's-look-at-file-formats" tabindex="-1">Let's Look At File Formats</h2>
<h3 id=".json" tabindex="-1"><code>.json</code></h3>
<p>JSON is natively supported by Style Dictionary, making it the easiest format to start with. Its rigid structure ensures compatibility across platforms and tools, but the verbose syntax of braces, quotes, and commas could be challenging for large or deeply nested token sets.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id=".yaml" tabindex="-1"><code>.yaml</code></h3>
<p>YAML is a human-readable, indentation-based syntax that reduces visual clutter, making it easier to manage for humans. It can especially useful for large, nested token sets and teams with non-developers, such as designers, working with token files.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">color</span><span class="token punctuation">:</span>
  <span class="token key atrule">primary</span><span class="token punctuation">:</span>
    $value<span class="token punctuation">:</span> <span class="token string">'#007bff'</span></code></pre>
<h3 id=".json5" tabindex="-1"><code>.json5</code></h3>
<p>JSON5 (JSON for humans) enhances JSON by allowing comments, trailing commas, and unquoted keys, making it a more forgiving and developer-friendly format. It’s a great option if you want JSON compatibility but also need to include notes or reduce syntax errors.</p>
<pre class="language-json5"><code class="language-json5"><span class="token punctuation">{</span>
  <span class="token comment">// Primary color</span>
  <span class="token property unquoted">color</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property unquoted">primary</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property unquoted">$value</span><span class="token operator">:</span> <span class="token string">'#007bff'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<h3 id=".hjson" tabindex="-1"><code>.hjson</code></h3>
<p>HJSON simplifies JSON by removing the need for strict punctuation, making it more human-readable. It could be a good middle ground between YAML’s simplicity and JSON’s structure.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id=".tokens-and-.tokens.json" tabindex="-1"><code>.tokens</code> and <code>.tokens.json</code></h3>
<p>The <code>.tokens</code> format follows the W3C Design Tokens Community Group specification, making it potentially future proof for new and existing tools and platforms. It retains the JSON structure but enforces standardised keys and metadata.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"$schema"</span><span class="token operator">:</span> <span class="token string">"https://design-tokens.org/schema.json"</span><span class="token punctuation">,</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="consuming-different-file-formats" tabindex="-1">Consuming Different File Formats</h2>
<p>Let's look how Style Dictionary can consume these formats and what, if any, extra tools we need to install to compile your Design Tokens to your desired output files.</p>
<h3 id="natively-supported-formats" tabindex="-1">Natively Supported Formats</h3>
<p>Style Dictionary natively supports <code>.json</code> and <code>.tokens</code> 'out of the box'. As previously shown in earlier articles to have your Design Tokens generate an output format (CSS Custom Properties for example) you need to define the source and platform details:</p>
<h4 id="json" tabindex="-1">JSON</h4>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.json'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// No extra setup needed</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'color.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h4 id="w3c-.tokens" tabindex="-1">W3C <code>.tokens</code></h4>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.tokens'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// Works like JSON</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'border.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="custom-parser-formats" tabindex="-1">Custom Parser Formats</h3>
<p>To use a file format that is not supported natively you would need to install the relevant library and add a custom parser to the configuration file.</p>
<h4 id="yaml" tabindex="-1">YAML</h4>
<p>To install the YAML library</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> yaml</code></pre>
<p>We would then create a custom parser for it</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> yaml <span class="token keyword">from</span> <span class="token string">'yaml'</span><span class="token punctuation">;</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'yaml-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.ya?ml$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> yaml<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We can then use <code>.yaml</code> as the source in the configuration</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.yaml'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// YAML files</span>
  <span class="token literal-property property">parsers</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'yaml-parser'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'typography.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="json5" tabindex="-1">JSON5</h3>
<p>To install the JSON5 library.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> json5</code></pre>
<p>We can then create a custom parser for it.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> json5 <span class="token keyword">from</span> <span class="token string">'json5'</span><span class="token punctuation">;</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'json5-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.json5$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> json5<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Again, we can then setup our configuration file to consume <code>.json5</code> Design Token files</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.json5'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">parsers</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'json5-parser'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'spacing.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h3 id="hjson" tabindex="-1">HJSON</h3>
<p>To install the HJSON library.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> hjson</code></pre>
<p>Again, we need to create a custom parser</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> hjson <span class="token keyword">from</span> <span class="token string">'hjson'</span><span class="token punctuation">;</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'hjson-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.hjson$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> hjson<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Then, we can set up the configuration file to use <code>.hjson</code> files</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'tokens/**/*.hjson'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">parsers</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'hjson-parser'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'animation.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2 id="bringing-it-all-together" tabindex="-1">Bringing it all together</h2>
<p>Not that I think you would or should decide to use multiple file formats to be consumed by Style Dictionary I think, for this article and example I'll tie all the options into a single config file.</p>
<p>If we have installed all the packages above we can then include them in our config file along with the custom parsers and also include these file formats as our possible sources:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> yaml <span class="token keyword">from</span> <span class="token string">'yaml'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> json5 <span class="token keyword">from</span> <span class="token string">'json5'</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> hjson <span class="token keyword">from</span> <span class="token string">'hjson'</span><span class="token punctuation">;</span>

<span class="token comment">// Register custom parsers for YAML, JSON5, and HJSON</span>
StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'yaml-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.ya?ml$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> yaml<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'json5-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.json5$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> json5<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

StyleDictionary<span class="token punctuation">.</span><span class="token function">registerParser</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'hjson-parser'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">pattern</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.hjson$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
  <span class="token function-variable function">parser</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> contents <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> hjson<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>contents<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Configure Style Dictionary</span>
<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// JSON (native)</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.tokens</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// TOKENS (native)</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.yaml</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// YAML (custom parser)</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.json5</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// JSON5 (custom parser)</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.hjson</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token comment">// HJSON (custom parser)</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">parsers</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'yaml-parser'</span><span class="token punctuation">,</span> <span class="token string">'json5-parser'</span><span class="token punctuation">,</span> <span class="token string">'hjson-parser'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token comment">// Custom parsers</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'all.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Build all platforms</span>
<span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let's create a simple set of Design Tokens for each file format:</p>
<p><strong>color.json</strong></p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6c757d"</span> <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>border.tokens</strong></p>
<pre class="language-tokens"><code class="language-tokens">{
  "$schema": "https://design-tokens.org/schema.json",
  "border": {
    "radius": {
      "small": { "$value": "4px" },
      "large": { "$value": "8px" }
    }
  }
}</code></pre>
<p><strong>typography.yaml</strong></p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">typography</span><span class="token punctuation">:</span>
  <span class="token key atrule">font</span><span class="token punctuation">:</span>
    <span class="token key atrule">family</span><span class="token punctuation">:</span>
      <span class="token key atrule">body</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">$value</span><span class="token punctuation">:</span> <span class="token string">'Roboto, sans-serif'</span> <span class="token punctuation">}</span>
      <span class="token key atrule">heading</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">$value</span><span class="token punctuation">:</span> <span class="token string">'Arial, sans-serif'</span> <span class="token punctuation">}</span>
    <span class="token key atrule">size</span><span class="token punctuation">:</span>
      <span class="token key atrule">small</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">$value</span><span class="token punctuation">:</span> <span class="token string">'0.875rem'</span> <span class="token punctuation">}</span>
      <span class="token key atrule">large</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token key atrule">$value</span><span class="token punctuation">:</span> <span class="token string">'1.25rem'</span> <span class="token punctuation">}</span></code></pre>
<p><strong>spacing.json5</strong></p>
<pre class="language-json5"><code class="language-json5"><span class="token punctuation">{</span>
  <span class="token property unquoted">spacing</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property unquoted">none</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property unquoted">$value</span><span class="token operator">:</span> <span class="token string">'0'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property unquoted">small</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property unquoted">$value</span><span class="token operator">:</span> <span class="token string">'0.5rem'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property unquoted">medium</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property unquoted">$value</span><span class="token operator">:</span> <span class="token string">'1rem'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property unquoted">large</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property unquoted">$value</span><span class="token operator">:</span> <span class="token string">'2rem'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>animation.hjson</strong></p>
<pre class="language-hjson"><code class="language-hjson">{
  animation: {
    duration: {
      short: { $value: "200ms" },
      medium: { $value: "500ms" },
      long: { $value: "1000ms" }
    }
  }
}</code></pre>
<p>When running the <code>build.js</code> file we will get a new CSS file containing all of these tokens as CSS custom properties:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--color-secondary</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
  <span class="token property">--border-radius-small</span><span class="token punctuation">:</span> 4px<span class="token punctuation">;</span>
  <span class="token property">--border-radius-large</span><span class="token punctuation">:</span> 8px<span class="token punctuation">;</span>
  <span class="token property">--typography-font-family-body</span><span class="token punctuation">:</span> Roboto<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--typography-font-family-heading</span><span class="token punctuation">:</span> Arial<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--typography-font-size-small</span><span class="token punctuation">:</span> 0.875rem<span class="token punctuation">;</span>
  <span class="token property">--typography-font-size-large</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-none</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  <span class="token property">--spacing-small</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-medium</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-large</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
  <span class="token property">--animation-duration-short</span><span class="token punctuation">:</span> 200ms<span class="token punctuation">;</span>
  <span class="token property">--animation-duration-medium</span><span class="token punctuation">:</span> 500ms<span class="token punctuation">;</span>
  <span class="token property">--animation-duration-long</span><span class="token punctuation">:</span> 1000ms<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>With the configuration and example tokens above, we’ve successfully demonstrated how to use different file formats to define design tokens and process them into a single output format.</p>
<p>This setup showcases the flexibility of Style Dictionary, enabling teams to choose the format that best suits their workflows while maintaining consistency in the output.</p>
<p>In the next part of this series, we’ll return to using <code>.json</code> as our design token format and dive into one of Style Dictionary’s most powerful features: automatic value transformations.</p>
<p>Style Dictionary allows you to define tokens in a single format, such as pixels (px), and then automatically convert them to other units based on your project’s needs. For example, you can set up tokens in px for mobile apps and have them automatically converted to rem for web development, ensuring consistent and accessible scaling.</p>
<p>We’ll also explore how these transformations can handle other use cases, like generating fallback colours for older browsers or converting colour formats from HEX to RGB. This flexibility reduces manual work and ensures your tokens are ready for use across multiple platforms. Stay tuned to see how these transformations can simplify and enhance your design token workflow!</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Creating A Generic Design System</title>
      <link href="https://www.alwaystwisted.com/articles/creating-a-generic-design-system.html"/>
      <updated>2024-11-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/creating-a-generic-design-system.html</id>
      <content type="html">
        <![CDATA[
        <p>In the last ~10 years of creating, updating, and building Design Systems as a front-end developer I've worked my way through a few possible solutions.</p>
<p>From building a simple component library using PHP, making use of Fractal, to helping build a customised documentation site using Eleventy … I have some thoughts.</p>
<p>The idea of creating a generic Design System that I can take with me for client work has always been something I've wanted to do, ever since working with a client 11 years ago and their pre-built themes for Sitecore CMS.</p>
<p>So, this is a start.</p>
<p>I've an idea on how I want to structure things, what languages I want to use and not use with the hope that I can create something that is useable and adaptable.</p>
<p>Of course, in reality, am I <em>relly</em> building a Design System or am I simply building another component library? We will see. I know I won't be creating anything in a design tool. I'm a front-end developer, I'll play to my strengths.</p>
<p>I do have grandiose ideas of streaming whilst I work on it. That might not come to fruition but I have decided to try and blog my way through it.</p>
<p>Naturally I've got a name for it. Mosaic.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Recently Closed Tabs - S01E01</title>
      <link href="https://www.alwaystwisted.com/articles/recently-closed-tabs-S01E01.html"/>
      <updated>2024-11-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/recently-closed-tabs-S01E01.html</id>
      <content type="html">
        <![CDATA[
        <p>I recently <a href="https://bsky.app/profile/sturobson.com/post/3laghd4htwv23">posted on Bluesky</a> about how I enjoyed Fridays on twitter in the past as a small group of people I followed would spend part of that day clearing out their open tabs from the week and sharing any juicy articles they found.</p>
<p>I followed this initial post with my opened tabs list that I read through, sharing the ones I found interesting.</p>
<p>I've decided to move this into a (potentially) weekly blog post too. It's 'just the links' no opinion, no summary. Simply a list of links I enjoyed reading. So here goes.</p>
<ul>
<li><a href="https://piccalil.li/blog/making-content-aware-components-using-css-has-grid-and-quantity-queries/">Making content-aware components using CSS :has(), grid, and quantity queries</a></li>
<li><a href="https://www.joshwcomeau.com/css/container-queries-introduction/">A Friendly Introduction to Container Queries</a></li>
<li><a href="https://medienbaecker.com/articles/focus-outlines">Beautiful focus outlines</a></li>
<li><a href="https://mayank.co/blog/css-reset-layer/">Your CSS reset should be layered</a></li>
<li><a href="https://hawkticehurst.com/2024/11/css-web-components-for-marketing-sites/">CSS Web Components for marketing sites</a></li>
<li><a href="https://heydonworks.com/article/the-button-element/">The Button Element</a></li>
<li><a href="https://css-tricks.com/come-to-the-light-dark-side/">Come to the light-dark() Side</a></li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Scaffolding Design System Components Using Plop.js</title>
      <link href="https://www.alwaystwisted.com/articles/scaffolding-design-system-components-using-plop-js.html"/>
      <updated>2024-11-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/scaffolding-design-system-components-using-plop-js.html</id>
      <content type="html">
        <![CDATA[
        <p>A tenet of Design Systems is a commitment to consistency, from creating and maintaining design tokens to standardising components and establishing uniform design patterns.</p>
<p>Creating a consistent folder structure with standardised files reinforces this principle, helping developers easily locate component files and understand their purpose. This repeatable structure reduces confusion, minimises onboarding time, and ensures that every component aligns with the system’s overall organisation and coding standards.</p>
<p>In this post, we’ll explore how to use plop.js to automate the creation of these files and folders, ensuring every component follows a consistent structure. We will walk through setting up plop.js, configuring templates, and creating prompts to streamline your workflow and keep your Design System and its components organised.</p>
<h2 id="what-is-plop.js%3F" tabindex="-1">What is plop.js?</h2>
<p><a href="https://plopjs.com/">Plop.js</a> is an open-source tool for automating file and folder creation, allowing us to generate consistent component structures with ease. By setting up templates and prompts, we can use plop.js to scaffold the necessary files for a component, ensuring everything follows our defined structure.</p>
<p>In this post, we will configure plop.js to generate the exact files and folders needed, making it simple to maintain consistency across all new components.</p>
<h2 id="setting-up-plop.js" tabindex="-1">Setting up plop.js</h2>
<p>To get us started, I have created a <a href="https://github.com/sturobson/component-scaffolding">new git repository which will have the finished code in</a>.</p>
<p>Let's begin by setting up the project with plop.js. After setting up the folder using <code>npm init</code> we need to install plop.js as a dependency</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save-dev plop</code></pre>
<p>Now create a configuration file <code>plopfile.js</code> that will be used to generate a component folder and files.</p>
<p>To start we need to add the basic configuration my importing plop</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = (plop) => {
  // This is where we’ll define our component generator
};</code></pre>
<p>We can then define our generator. To start with we can give the generator a description, this is a helpful label especially if you plan to create several generators. If a user runs plop without specifying a generator it will display a list of generators available with these descriptions which can help the user understand the purpose of each option.</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = (plop) => {
  plop.setGenerator('component', {
    description: 'Create a new component with files and folders',
  // more code</code></pre>
<p>As we are creating a generator for components we would need to ask the user the component name so it can generator appropriate files and folders with that name as needed:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = (plop) => {
  plop.setGenerator('component', {
    description: 'Create a new component with files and folders',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Component name?',
      },
    ],
  // more code</code></pre>
<p>To start with let's generate an <code>.njk</code>, <code>.scss</code>, and <code>.js</code> file for the component. We can give the <code>.njk</code> file the component name that is inputted, the <code>.scss</code> and <code>.js</code> files will be both have the name of <code>index</code> so importing it simpler.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@use</span> <span class="token string">'component-name'</span><span class="token punctuation">;</span>
<span class="token comment">// instead of</span>
<span class="token keyword">@use</span> <span class="token string">'component-name/component-name.scss'</span><span class="token punctuation">;</span></code></pre>
<p>For plop to create files we need to give the <code>plopfile.js</code> some actions, for this we are adding files so we use the type of <code>add</code>:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = (plop) => {
  plop.setGenerator('component', {
    description: 'Create a new component with files and folders',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Component name?',
      },
    ],
    actions: [
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/{{pascalCase name}}.njk'
      },
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/index.scss'
      },
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/index.js'
      },
    ],
  });
};</code></pre>
<h3 id="let's-generate" tabindex="-1">Let's Generate</h3>
<p>With a basic set of actions to create files in a folder we can start to use plop to scaffold new components. With the dependency installed we can add a build script to the <code>package.json</code>:</p>
<pre class="language-bash"><code class="language-bash"><span class="token string">"scripts"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
  <span class="token string">"build"</span><span class="token builtin class-name">:</span> <span class="token string">"npm run plop"</span>,
  <span class="token string">"plop"</span><span class="token builtin class-name">:</span> <span class="token string">"plop component"</span>
<span class="token punctuation">}</span></code></pre>
<p>We can now run <code>npm run build</code> on the command line. This will give us a prompt:</p>
<p><img src="/images/articles/prompt-1.png" alt="a screenshot of terminal code where we have run 'npm run build' and are asked 'Component name?'" loading="lazy" decoding="async"></p>
<p>Giving the prompt a name and hitting return will generate the three files in a folder</p>
<p><img src="/images/articles/prompt-2.png" alt="a screenshot of terminal code where we have run 'npm run build' and are asked 'Component name? We have filled that out with 'button' and it shows that it has created three new files'" loading="lazy" decoding="async"></p>
<p>note: You can see in the <code>path</code> we have <code>{{pascalCase name}}</code>. <code>pascalCase</code> is here if you give the prompt more than one word for your component. I'm going to change this to <code>kebabCase</code> for the rest of this article.</p>
<h2 id="using-templates" tabindex="-1">Using Templates</h2>
<p>Each file generated using plop can have a associated Handlebars template file, ensuring consistent, structured content is created automatically during the plop process.</p>
<p>Let's say we want to have something like this in your generated Nunjucks and Sass files:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>class-name<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@forward</span> <span class="token string">'config/variables'</span> <span class="token module-modifier keyword">as</span> *<span class="token punctuation">;</span>

<span class="token selector">.class-name </span><span class="token punctuation">{</span>
<span class="token punctuation">}</span></code></pre>
<p>We can create a new <code>.hbs</code> file for each of these and add the content needed so plop can generate them.</p>
<pre class="language-hbs"><code class="language-hbs"><span class="token block keyword">//</span> <span class="token variable">template</span><span class="token punctuation">/</span><span class="token variable">component</span><span class="token punctuation">.</span><span class="token variable">njk</span><span class="token punctuation">.</span><span class="token variable">hbs</span>

<span class="token punctuation">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token punctuation">=</span><span class="token string">'{{kebabCase name}}'</span><span class="token punctuation">></span>

<span class="token punctuation">&lt;</span><span class="token punctuation">/</span><span class="token variable">div</span><span class="token punctuation">></span></code></pre>
<pre class="language-hbs"><code class="language-hbs"><span class="token block keyword">//</span> <span class="token variable">template</span><span class="token punctuation">/</span><span class="token variable">index</span><span class="token punctuation">.</span><span class="token variable">scss</span><span class="token punctuation">.</span><span class="token variable">hbs</span> <span class="token punctuation">@</span><span class="token variable">use</span> <span class="token string">'config/variables'</span> <span class="token variable">as</span> <span class="token punctuation">*</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token variable">kebabCase</span> <span class="token variable">name</span><span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre>
<p>We can reference these files in plopfile.js using templateFile:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = (plop) => {
  plop.setGenerator('component', {
    description: 'Create a new component with HTML and SCSS files',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Component name?',
      },
    ],
    actions: [
      {
        type: 'add',
        path: 'components/{{kebabCase name}}/{{kebabCase name}}.njk',
        templateFile: 'plop-templates/component.njk.hbs',
      },
      {
        type: 'add',
        path: 'components/{{kebabCase name}}/index.scss',
        templateFile: 'plop-templates/index.scss.hbs',
      },
      {
        type: 'add',
        path: 'src/components/{{pascalCase name}}/index.js',
      },
    ],
  });
};</code></pre>
<h2 id="everything-is-a-component" tabindex="-1">Everything is a component</h2>
<p>When architecting the structure and naming conventions for your components you may find it easier to separate 'types of component' into separate folders. For example, if you use the ideas around <a href="https://bradfrost.com/blog/post/atomic-web-design/">Atomic Design</a> and want to follow the structure for your components as atoms, molecules, and organisms you may want to split out these types of components.</p>
<p>We can do this by adding a further prompt that can add a namespace to the component as well as put these components in the correct folder.</p>
<p>Adding another prompt that is a list will give the user only one option to pick which will aid consistency. Rather than requiring them to spell the type of token correctly or remember the name-spacing we can get the information from this prompt and generate the components folder and file structure accordingly.</p>
<p>Let's add a new prompt</p>
<pre class="language-JavaScript"><code class="language-JavaScript">{
  type: 'list',
  name: 'type',
  message: 'Is this component an atom, molecule, or organism?',
  choices: ['atom', 'molecule', 'organism'],
},</code></pre>
<p><img src="/images/articles/prompt-3.png" alt="a screenshot of terminal code where we have run 'npm run build' and are asked 'Component name?' After this it asks if the component is an atom, molecule, or organism, and gives us a list of those items to select" loading="lazy" decoding="async"></p>
<p>We still need to update the paths and any templates to make use of this prompt. The prompt gives us the <code>{{type}}</code> which takes the response from the <code>choices</code> in the prompt.</p>
<pre class="language-JavaScript"><code class="language-JavaScript">actions: [
  {
 type: 'add',
 path: 'components/{{type}}/{{type}}-{{kebabCase name}}/{{type}}-{{kebabCase name}}.njk',
 templateFile: 'plop-templates/component.njk.hbs',
  },
  {
 type: 'add',
 path: 'components/{{type}}/{{type}}-{{kebabCase name}}/index.scss',
 templateFile: 'plop-templates/index.scss.hbs',
  },
  {
 type: 'add',
 path: 'components/{{type}}/{{type}}-{{kebabCase name}}/index.js',
  },
],</code></pre>
<p><img src="/images/articles/prompt-4.png" alt="a screenshot of terminal code where we have run 'npm run build' and are asked 'Component name?' After this it asks if the component is an atom, molecule, or organism, and gives us a list of those items to select. Selecting atom - it creates three files" loading="lazy" decoding="async"></p>
<p>As you can see from the image we created a new component called <code>atoms-button</code>. The more mature your Design System becomes the more potential components you will had and may need to create. Rather than <code>atoms-</code>, <code>molecules-</code>, and <code>organisms-</code> as the name space, let's create a quick help that will abbreviate these to <code>a-</code>, <code>m-</code>, and <code>o-</code>.</p>
<pre class="language-JavaScript"><code class="language-JavaScript">// Custom helper to define type abbreviation
plop.setHelper('typeAbbreviation', (type) => {
  switch (type) {
    case 'atom': return 'a';
    case 'molecule': return 'm';
    case 'organism': return 'o';
    default: return '';
  }
});</code></pre>
<p>We still need to update the templates for the <code>.njk</code> and <code>.scss</code> file. So let's update the <code>plop-templates/component.njk.hbs</code> and <code>plop-templates/index.scss.hbs</code> files to make use of the <code>{{type}}</code> too.</p>
<pre class="language-hbs"><code class="language-hbs"><span class="token block keyword">//</span> <span class="token variable">template</span><span class="token punctuation">/</span><span class="token variable">component</span><span class="token punctuation">.</span><span class="token variable">njk</span><span class="token punctuation">.</span><span class="token variable">hbs</span>

<span class="token punctuation">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token punctuation">=</span><span class="token string">'{{typeAbbreviation type}}-{{kebabCase name}}'</span><span class="token punctuation">></span>

<span class="token punctuation">&lt;</span><span class="token punctuation">/</span><span class="token variable">div</span><span class="token punctuation">></span></code></pre>
<pre class="language-hbs"><code class="language-hbs"><span class="token block keyword">//</span> <span class="token variable">template</span><span class="token punctuation">/</span><span class="token variable">index</span><span class="token punctuation">.</span><span class="token variable">scss</span><span class="token punctuation">.</span><span class="token variable">hbs</span> <span class="token punctuation">@</span><span class="token variable">use</span> <span class="token string">'config/variables'</span> <span class="token variable">as</span> <span class="token punctuation">*</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token variable">typeAbbreviation</span>
  <span class="token variable">type</span>
<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token variable">-</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token variable">kebabCase</span> <span class="token variable">name</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
<span class="token punctuation">{</span> <span class="token punctuation">}</span></code></pre>
<p><img src="/images/articles/prompt-5.png" alt="a screenshot of terminal code where we have run 'npm run build' and are asked 'Component name?' After this it asks if the component is an atom, molecule, or organism, and gives us a list of those items to select. Selecting atom - it creates three files. This time the atoms is abbreviated to a- for the component files and folder name" loading="lazy" decoding="async"></p>
<h2 id="what-else-to-generate-for-a-design-systems-component" tabindex="-1">What else to generate for a Design Systems component</h2>
<p>No we have a basic component folder and file structure generator we can think of what else we might need.</p>
<h3 id="a-read-me-file" tabindex="-1">a read me file</h3>
<pre class="language-JavaScript"><code class="language-JavaScript">{
  type: 'add',
  path: 'src/components/{{type}}s/{{typeAbbreviation type}}-{{kebabCase name}}/README.md',
  templateFile: 'plop-templates/README.md.hbs',
}</code></pre>
<h3 id="adding-a-creation-date" tabindex="-1">adding a creation date</h3>
<p>Creating a new helper we can add a 'creation date' to files we need to:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">  plop.setHelper('creationDate', () => new Date().toLocaleDateString());</code></pre>
<p>Which could be used in the README.md template:</p>
<pre class="language-handlebars"><code class="language-handlebars"><span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">typeAbbreviation</span> <span class="token variable">type</span><span class="token delimiter punctuation">}}</span></span>-<span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">kebabCase</span> <span class="token variable">name</span><span class="token delimiter punctuation">}}</span></span>
Documentation Created on:
<span class="token handlebars language-handlebars"><span class="token delimiter punctuation">{{</span><span class="token variable">creationDate</span><span class="token delimiter punctuation">}}</span></span>

--- ## Usage ## Code Example ## Variants ## Props</code></pre>
<h2 id="" tabindex="-1"></h2>
<p>By making use of <code>plop.js</code> we have automated a consistent structure for our component files, helping maintain organisation and clarity in our codebase. This initial setup can be easily adapted to your differing projects. You might consider adding test files, component design tokens <code>.json</code>, moving Sass into a separate folder. Adjusting <code>plop.js</code> to match your team's needs and workflow are simple with the flexibility it offers.</p>
<p>I hope this short tutorial has helped you think about a practical approach to enhancing your Design System's scalability and efficiency by automating a small part.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 2) - Outputting to Different Formats with Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-2.html"/>
      <updated>2024-10-31T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-2.html</id>
      <content type="html">
        <![CDATA[
        <p>In the first tutorial in this series I walked us through creating up a simple Style Dictionary setup that can transform your Design Tokens (in <code>.json</code>) to different formats (a <code>.css</code> file of CSS Custom Properties and Sass variables in a <code>.scss</code> file). In this tutorial we will go through the other 'built-in' formats that are available, how to set them up, what they are for, and what they would look like.</p>
<h2 id="defining-design-tokens" tabindex="-1">Defining Design Tokens</h2>
<p>Let's look again at the Design Tokens from the first part in this series. We have a couple of colours, some spacing units, and some typography decisions.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6c757d"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span><span class="token punctuation">,</span>
    <span class="token property">"none"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.5rem"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"typography"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span><span class="token punctuation">,</span>
        <span class="token property">"body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Roboto, sans-serif"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontSize"</span><span class="token punctuation">,</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.25rem"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="built-in-formats" tabindex="-1">Built In Formats</h2>
<p>Out of the box Style Dictionary comes with several built-in formats you can use to convert your Design Tokens from <code>.json</code> to a file format that can be used with various platforms and codebases.</p>
<p>There are formats for CSS, Sass, LESS, Stylus, JavaScript, TypeScript, Android, iOS, Swift, and JSON. With all these possibilities we can truly keep design decisions in sync across the various platforms we need to. This also allows you to scale to new codebases more easily because the Design Token <code>.json</code> stays the same but can output to what you need, as needed.</p>
<p>Let's go through a couple of them to see what how we can turn our Design Tokens into useable code for our projects. You can follow along and <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/02-Different-Formats">see the results in the fresh branch of the git repository</a>.</p>
<h3 id="css" tabindex="-1">CSS</h3>
<p>We've already seen this in <a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-1">the first article</a>. The format <code>css/variables</code> takes the <code>.json</code> and creates a <code>.css</code> with the Design Tokens generated as CSS Custom Properties.</p>
<h3 id="css-preprocessors" tabindex="-1">CSS Preprocessors</h3>
<h4 id="sass" tabindex="-1">Sass</h4>
<h5 id="variables" tabindex="-1">Variables</h5>
<p>Again, from the first article. The format <code>scss/variables</code> can create a file of Sass variables based on the Design Tokens in the <code>.scss</code> format.</p>
<h5 id="map-(flat)" tabindex="-1">Map (flat)</h5>
<p>Using the format <code>scss/map-flat</code> provides a Sass map of the Design Tokens. To incorporate this into the example git repository we need to add some additional code to the <code>build.js</code> file.</p>
<p>We can add this to the existing <code>scss</code> platform in <code>build.js</code>. Platforms in Style Dictionary define the different output formats where you want your Design Tokens to be used. Each platform has unique configurations for how the tokens are to be transformed, formmated, and written to files.</p>
<p>To add a flat Sass Map to our project we need to add a new destination for where the file is created and tell Style Dictionary what format to use. We can do this by adding:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens-map.scss'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/map-flat'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>After the existing destination and format for <code>scss/variabkes</code>. The complete file would look like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/css/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/scss/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'_variables.scss'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens-map.scss'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/map-flat'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Once we build the tokens again we will get a new <code>tokens-map.scss</code> file withe the following content:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$tokens</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token string">'color-primary'</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">,</span>
  <span class="token string">'color-secondary'</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">,</span>
  <span class="token string">'spacing-none'</span><span class="token punctuation">:</span> 0<span class="token punctuation">,</span>
  <span class="token string">'spacing-small'</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">,</span>
  <span class="token string">'spacing-medium'</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">,</span>
  <span class="token string">'typography-font-family-body'</span><span class="token punctuation">:</span> Roboto<span class="token punctuation">,</span>
  sans-serif<span class="token punctuation">,</span>
  <span class="token string">'typography-font-size-base'</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">,</span>
  <span class="token string">'typography-font-size-lg'</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h5 id="map-(deep)" tabindex="-1">Map (deep)</h5>
<p>We can use the Style Dictionary format <code>scss/map-deep</code> to generate a list of Sass variables and then a nested Sass map that references them.</p>
<p>Again, we can add the new format and destination to our <code>build.js</code> file to then have Style Dictionary create a new <code>.scss</code> file with variables and map.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  destination<span class="token operator">:</span> <span class="token string">'tokens-map-deep.scss'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/map-deep'</span><span class="token punctuation">,</span>  <span class="token comment">// Deep map format</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>Getting Style Dictionary to generate the various files will now create this new Sass file which would look like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$color-primary</span></span><span class="token punctuation">:</span> #007bff <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-secondary</span></span><span class="token punctuation">:</span> #6c757d <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-none</span></span><span class="token punctuation">:</span> 0 <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-small</span></span><span class="token punctuation">:</span> 0.5rem <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-medium</span></span><span class="token punctuation">:</span> 1rem <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-family-body</span></span><span class="token punctuation">:</span> Roboto<span class="token punctuation">,</span> sans-serif <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-size-base</span></span><span class="token punctuation">:</span> 1rem <span class="token statement keyword">!default</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-size-lg</span></span><span class="token punctuation">:</span> 1.25rem <span class="token statement keyword">!default</span><span class="token punctuation">;</span>

<span class="token property"><span class="token variable">$tokens</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token string">'color'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
    <span class="token string">'primary'</span><span class="token punctuation">:</span> <span class="token variable">$color-primary</span><span class="token punctuation">,</span>
    <span class="token string">'secondary'</span><span class="token punctuation">:</span> <span class="token variable">$color-secondary</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token string">'spacing'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
    <span class="token string">'none'</span><span class="token punctuation">:</span> <span class="token variable">$spacing-none</span><span class="token punctuation">,</span>
    <span class="token string">'small'</span><span class="token punctuation">:</span> <span class="token variable">$spacing-small</span><span class="token punctuation">,</span>
    <span class="token string">'medium'</span><span class="token punctuation">:</span> <span class="token variable">$spacing-medium</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token string">'typography'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
    <span class="token string">'font'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
      <span class="token string">'family'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
        <span class="token string">'body'</span><span class="token punctuation">:</span> <span class="token variable">$typography-font-family-body</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span><span class="token punctuation">,</span>
      <span class="token string">'size'</span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
        <span class="token string">'base'</span><span class="token punctuation">:</span> <span class="token variable">$typography-font-size-base</span><span class="token punctuation">,</span>
        <span class="token string">'lg'</span><span class="token punctuation">:</span> <span class="token variable">$typography-font-size-lg</span><span class="token punctuation">,</span>
      <span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h3 id="javascript-and-typescript" tabindex="-1">JavaScript and TypeScript</h3>
<p>Style Dictionary has 3 JavaScript and 1 TypeScript built-in formats that can be used to generate various forms of JavaScript for various needs and projects.</p>
<h4 id="javascript-(object)" tabindex="-1">JavaScript (Object)</h4>
<p>Using the format <code>javascript/object</code> will export the tokens as a structured JavaScript object using the hierarchy defined in the Design Tokens. These can be used in your Vue or React projects that make use of direct JavaScript imports. In React, for example, you can import the tokens and apply them directly within a CSS-in-JS solution (like styled-components).</p>
<p>To add a JavaScript format to our existing <code>build.js</code> file we will als need to include a new platform (<code>js</code>) so Style Dictionary knows what to do when generating the code.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">js</span><span class="token operator">:</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/js/'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
 <span class="token punctuation">{</span>
   <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens.js'</span><span class="token punctuation">,</span>
   <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/object'</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>This will then generate a JavaScript file of the tokens like this (I've also popped this into a <code>js</code> folder to try to keep the build folder a little cleaner):</p>
<pre class="language-JavaScript"><code class="language-JavaScript">var _styleDictionary = {
  "color": {
    "primary": {
      "$value": "#007bff",
      "filePath": "src/tokens/tokens.json",
      "isSource": true,
      "$type": "color",
      "original": {
        "$value": "#007bff",
        "$type": "color"
      },
      "name": "ColorPrimary",
      "attributes": {
        "category": "color",
        "type": "primary"
      },
      "path": [
        "color",
        "primary"
      ]
    },
  // more code followed</code></pre>
<h4 id="javascript-(module-flat)" tabindex="-1">JavaScript (Module Flat)</h4>
<p>This built-in format creates a file of flat JavaScript objects. This could be great for projects that need to access tokens frequently and directly, without needing to navigate the structure of the Design Tokens to get to it. This flat output may also be better for projects that use a JavaScript bundler. A flat object also aligns more closely with how Design Tokens can be 'directly' in CSS or Sass as Custom Properties and Variables.</p>
<p>Adding the below to the <code>files</code> within our <code>js</code> platform in the <code>build.js</code> file:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens-flat.js'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/module-flat'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>Will give us the flat JavaScript objects:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">module.exports = {
  "ColorPrimary": "#007bff",
  "ColorSecondary": "#6c757d",
  "SpacingNone": "0",
  "SpacingSmall": "0.5rem",
  "SpacingMedium": "1rem",
  "TypographyFontFamilyBody": "Roboto, sans-serif",
  "TypographyFontSizeBase": "1rem",
  "TypographyFontSizeLg": "1.25rem"
};</code></pre>
<h4 id="javascript-(umd)" tabindex="-1">JavaScript (UMD)</h4>
<p>Generating a <code>.js</code> file using this format could allow tokens to be accessed as global variables when CommonJS or AMD imports are not available. This could work well for older or mixed environments where some flexibility is key. This format can be particularly handy in environments that cannot guarantee ES module support.</p>
<p>Adding the new <code>destionation</code> and <code>format</code>:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens-umd.js'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'javascript/umd'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>Will generate a JavaScript file that looks like this which includes the Universal Module Definition wrapper to make sure the code inside can be used in multiple environments:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">(function(root, factory) {
  if (typeof module === "object" && module.exports) {
    module.exports = factory();
  } else if (typeof exports === "object") {
    exports["_styleDictionary"] = factory();
  } else if (typeof define === "function" && define.amd) {
    define([], factory);
  } else {
    root["_styleDictionary"] = factory();
  }
}(this, function() {
  return {
  "color": {
    "primary": {
      "$value": "#007bff",
      "filePath": "src/tokens/tokens.json",
      "isSource": true,
      "$type": "color",
      "original": {
        "$value": "#007bff",
        "$type": "color"
      },
      "name": "ColorPrimary",
      "attributes": {
        "category": "color",
        "type": "primary"
      },
      "path": [
        "color",
        "primary"
      ]
    },</code></pre>
<h4 id="typescript-(es6-declarations)" tabindex="-1">TypeScript (ES6 Declarations)</h4>
<p>This format creates a <code>.d.ts</code> file of your Design Tokens to provide TypeScript definitions so that TypeScript projects can use the tokens with type safety and autocomplete support. This does not output the actual token values but instead provides types, ensuring that TypeScript can recognise and check token names and types within code.</p>
<p>Let's add a new platform for TypeScript to our <code>build.js</code> file to generate the <code>.d.ts</code> file:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token literal-property property">ts</span><span class="token operator">:</span> <span class="token punctuation">{</span>
  <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'js'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/types/'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
 <span class="token punctuation">{</span>
   <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'tokens.d.ts'</span><span class="token punctuation">,</span>
   <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'typescript/es6-declarations'</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>This will generate:</p>
<pre class="language-TypeScript"><code class="language-TypeScript">export const ColorPrimary : string;
export const ColorSecondary : string;
export const SpacingNone : string;
export const SpacingSmall : string;
export const SpacingMedium : string;
export const TypographyFontFamilyBody : string;
export const TypographyFontSizeBase : string;
export const TypographyFontSizeLg : string;</code></pre>
<h3 id="android" tabindex="-1">Android</h3>
<p>Using <code>android/resources</code> will generate an XML resource file containing the Design Tokens that follows Android's resource naming conventions.</p>
<p>We will need to define a new platform in our <code>build.js</code> file and add the relevant <code>destination</code> and <code>format</code> so Style Dictionary can generate the XML file correctly:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">android: {
  transformGroup: 'android',
  buildPath: 'build/android/',
  files: [
 {
   destination: 'values/tokens.xml',
   format: 'android/resources',
 },
  ],
},</code></pre>
<p>This will generate a file of mixed types within a single <code>&lt;resources&gt;</code> tag for Android development:</p>
<pre class="language-xml"><code class="language-xml"><span class="token prolog">&lt;?xml version="1.0" encoding="UTF-8"?></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>resources</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>color</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color_primary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>#ff007bff<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>color</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>color</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>color_secondary<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>#ff6c757d<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>color</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_none<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_small<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>0.5rem<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spacing_medium<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1rem<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>string</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>typography_font_family_body<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Roboto, sans-serif<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>string</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>typography_font_size_base<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>16.00sp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dimen</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>typography_font_size_lg<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>20.00sp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dimen</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>resources</span><span class="token punctuation">></span></span></code></pre>
<h3 id="ios-%2F-swift" tabindex="-1">iOS / Swift</h3>
<h4 id="ios-swift-(class)" tabindex="-1">iOS Swift (class)</h4>
<p>This <code>format</code> will create a Swift class file that defines the Design Tokens as static properties which can be directly accessed within iOS code ideal when you need to use Design Tokens as constants throughout the codebase.</p>
<p>Again, we will need to define a new platform in our <code>build.js</code> file for this format:</p>
<pre class="language-JavaScript"><code class="language-JavaScript">ios: {
  transformGroup: 'ios-swift',
  buildPath: 'build/ios/',
  files: [
 {
   destination: 'Tokens.swift',
   format: 'ios-swift/class.swift',
   className: 'Tokens', // Name of the Swift class
 },
  ],
},</code></pre>
<p>When run the <code>build.js</code> file will then create a new file in <code>build/ios/</code> called <code>Tokens.swift</code> with the following:</p>
<pre class="language-swift"><code class="language-swift"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> colorPrimary <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.000</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.482</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">1.000</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> colorSecondary <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">0.424</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">0.459</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">0.490</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingMedium <span class="token operator">=</span> 1rem
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingNone <span class="token operator">=</span> <span class="token number">0</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> spacingSmall <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">.</span>5rem
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> typographyFontFamilyBody <span class="token operator">=</span> <span class="token class-name">Roboto</span><span class="token punctuation">,</span> sans<span class="token operator">-</span>serif
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> typographyFontSizeBase <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">16.00</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> typographyFontSizeLg <span class="token operator">=</span> <span class="token class-name">CGFloat</span><span class="token punctuation">(</span><span class="token number">20.00</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span></code></pre>
<p>Going through the above built-in formats only shows an example of what is possible 'out of the box'. There are also built-in formats for the Less and Stylus CSS preprocessors, for various outputs of JSON, and a few more options for iOS and Swift.</p>
<p>Having all these options means you have the ability to push your Design Tokens across teams, projects, and platforms and create consistency and trust in your products. Using Design Tokens as a source of truth for your design decisions can also help streamline development and updates.</p>
<p>These are 'built-in' formats which means we can also create our own custom formats, for example, with <code>scss/map-deep</code> I would want a separate <code>.scss</code> file for my Sass variables and then have the map in a different file rather than a single file with both.</p>
<p>While Style Dictionary’s built-in formats cover a wide range, customisation is often essential.</p>
<p>In a future article, we’ll look into how to create custom formats tailored to your unique needs. Whether you need to separate variables from maps in Sass or define specialised token structures, custom formats will allow you to adapt Style Dictionary even further to fit your project.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Weeknotes S01E01</title>
      <link href="https://www.alwaystwisted.com/articles/weeknotes-S01E01.html"/>
      <updated>2024-10-25T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/weeknotes-S01E01.html</id>
      <content type="html">
        <![CDATA[
        <p>I'm not sure if I'll remember to do this regularly, but I'm hoping that the bare bones of a new setup in Obsidian will have me making notes during the week to collate on a Friday.</p>
<h2 id="writing" tabindex="-1">Writing</h2>
<p>This week I wrote 3 new articles (not including this week note):</p>
<p><a href="https://www.alwaystwisted.com/articles/creating-design-system-friendly-snowflakes-with-utility-classes.html">Creating Design System-Friendly Snowflakes with Utility Classes</a></p>
<p><a href="https://www.alwaystwisted.com/articles/what-else-can-we-do-with-design-tokens.html">What Else Can We Do With Design Tokens?</a></p>
<p><a href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-1.html">A Design Tokens Workflow (part 1) - Getting Started With Style Dictionary</a></p>
<p>I've done a few tweaks to the website, I've removed the 'yellow' colour theme option as it only really worked in dark mode and I didn't want to do something for one theme. Six colour themes is more than enough 😭.</p>
<h2 id="looking-for-work" tabindex="-1">Looking For Work</h2>
<p>Oh yes, I'm still looking for work. Todays task after publishing this is to get 'into the weeds' of what services I can provide.</p>
<p>Although I am more than happy to join existing teams in creating or maintaining their design system and helping agencies in turning around designs into front-end code I'm looking at shorter, focused services I can provide.</p>
<p>If you think you've got a project in mind, <a href="mailto:hire@sturobson.com">let's chat</a>.</p>
<h2 id="watched" tabindex="-1">Watched</h2>
<p>I don't know if it's (more often than not) because of the ability to 'binge watch' series or if there's actually been a 'drought' of good content we can watch at the end of the day.</p>
<p>Although we're nearing the finale of 'Spooky Season' my partner isn't a fan of the horror genre my chances to watch this years tranche of halloween horror is pretty slim.</p>
<h3 id="sweetpea" tabindex="-1">Sweetpea</h3>
<p>We watched Sweetpea, we both enjoyed it. Not to give any spoilers, we're looking forward to series two already.</p>
<h3 id="fl.-vs-boone" tabindex="-1">FL. vs Boone</h3>
<p>I don't remember how I came to it - but I've been watching several Live Courts from the US via <a href="https://www.youtube.com/@TheEmilyDBaker">Emily D. Bakers YouTube Channel</a>. It started about a third of the way through Depp v. Heard and I've just stayed with the live streams either in the background or for a short period before bed.</p>
<h3 id="woman-of-the-hour" tabindex="-1">Woman Of The Hour</h3>
<p>Based on the true story of <a href="https://en.wikipedia.org/wiki/Rodney_Alcala">The Dating Game Killer</a> and a directorial debut from <a href="https://en.wikipedia.org/wiki/Anna_Kendrick">Anna Kendrick</a> who plays the lead - I really enjoyed the look of this when it was 'on the set' of the game show. The treatment to those scenes felt more real to me than <a href="https://www.imdb.com/title/tt14966898/">Late Night With The Devil</a> which I believe was let down by the black and white scenes looking too 'new'. Going into this I didn't know it was based on a 'true crime' story. I enjoyed it.</p>
<h2 id="read" tabindex="-1">Read</h2>
<p>I haven't read much this week, the current book on the Kindle is <a href="https://www.goodreads.com/book/show/64623481-the-september-house">The September House</a> but I don't think I've managed to read a word.</p>
<h2 id="listened" tabindex="-1">Listened</h2>
<h3 id="podcasts" tabindex="-1">Podcasts</h3>
<p>I've a vague memory of watching Halloween on an old black and white TB, late at night with the contrast down so the images on the screen were dark grey on black. I think this was the start of me becoming a fan of the horror genre.</p>
<p>I don't listen to many podcasts, there's a couple of Design Systems-related ones and the odd true crime series but I do look out for an interesting episode of <a href="https://podcasts.bloody-disgusting.com/#horrorqueers">Horror Queers</a>.</p>
<p>This weeks was a two hour dive into Black Christmas from 1974. Coming out before Halloween, there's still bits that make me jump. This film (and it's 2019 remake (but not the 2006 remake)) are always on my Christmas/Horror watch list.</p>
<h3 id="music" tabindex="-1">Music</h3>
<p>Did you know that The Smashing Pumpkins released - Mellon Collie and the Infinite Sadness - a whole day earlier in the UK compared to the rest of the world‽ Did you know it turned 29 years old?</p>
<p>This album came out in my first year of A-Levels - a perfect sound track to the next two years. I also managed to snag a ticket to see them in the tin shed that is/was(?) Wembley Arena on the tour.</p>
<p>I had a look on Spotyify at the number of plays per track and it seems not many folks listened to the second of this double album.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Design Tokens Workflow (part 1) - Getting Started With Style Dictionary</title>
      <link href="https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-1.html"/>
      <updated>2024-10-24T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-design-tokens-workflow-part-1.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="what-are-design-tokens" tabindex="-1">What are Design Tokens</h2>
<p>Design Tokens have become a widely-adopted method to store design decisions (such as colours, typography, spacing, border-radius, and other visual properties) across products, applications, and websites.</p>
<p>They help create a shared language between design and development (and beyond), ensuring consistency across a digital product’s design and implementation.</p>
<p>By converting these design decisions into platform-specific formats (like CSS variables for the web or XML for Android), design tokens ensure that your visual guidelines are accurately applied no matter where they are used.</p>
<p>To do this efficiently, we can use tools that automate the process. <a href="https://v4.styledictionary.com">Style Dictionary</a> is one popular open-source tool that can be used to take Design Tokens in a <code>.json</code> format and generate relevant, specific files for your needs. There are also other tools, such as Theo, Thing1, Thing2, and Thing3.</p>
<p>In this tutorial, and for future tutorials in the series, I'll be using Style Dictionary. I have created a <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/01-Getting-Started">git repository</a> that will include the end results.</p>
<h2 id="initial-setup" tabindex="-1">Initial setup</h2>
<p>To get started, you’ll need to install Style Dictionary. It can either be installed globally:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> style-dictionary</code></pre>
<p>Or it can be installed as a dependency of your project. It is most likely that you would install Style Dictionary this way:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-D</span> style-dictionary</code></pre>
<p>We can create a new folder (project) and open it with our text editor to get started.</p>
<p>As we will be using <a href="https://www.npmjs.com">npm</a> we will need to initialise this in the project and fill out any relevant questions posed in the terminal.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> init</code></pre>
<p>We should then have a new <code>package.json</code> and <code>package-lock.json</code> file. The <code>package.json</code> file could look something like this:</p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">{</span>
  <span class="token string">"name"</span><span class="token builtin class-name">:</span> <span class="token string">"style-dictionary-starter"</span>,
  <span class="token string">"version"</span><span class="token builtin class-name">:</span> <span class="token string">"0.1.0"</span>,
  <span class="token string">"devDependencies"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
    <span class="token string">"style-dictionary"</span><span class="token builtin class-name">:</span> <span class="token string">"^4.1.4"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="creating-a-build-script" tabindex="-1">Creating a build script</h3>
<p>To get Style Dictionary to create the files we need we need to create a build script. To start with in this series we are going to have a small set of example Design Tokens in <code>.json</code> that we are going to use to create a CSS file of CSS custom properties.</p>
<p>Here's the full build script:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Let's go through this, line by line to see what the script is doing.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span></code></pre>
<p>Imports Style Dictionary to process tokens.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span></code></pre>
<p>Creates a new instance of StyleDictionary using a configuration object which will handle the processing and building of the design tokens based on the provided settings.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span>src<span class="token operator">/</span>tokens<span class="token comment">/**/</span><span class="token operator">*</span><span class="token punctuation">.</span>json<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre>
<p>Specifies the location of the design token files. The pattern <code>**/*.json</code> tells Style Dictionary to look for any <code>.json</code> files in the directory and its sub directories.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span></code></pre>
<p>Begins the configuration for different platforms. Each platform defines how and where the design tokens should be transformed and outputted to.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span></code></pre>
<p>Defines a platform named css. This platform will transform the design tokens into a format suitable for CSS usage.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span></code></pre>
<p>Specifies the transform group css. This group tells Style Dictionary to use a set of predefined transforms that convert tokens to CSS-compatible values.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span></code></pre>
<p>Sets the output directory to build/. The processed files generated by Style Dictionary will be placed in this directory.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
 <span class="token punctuation">{</span>
  <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
 <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre>
<p>This array defines the files that will be generated. Each object in this array represents a separate output file. This specific object configures a file named <code>variables.css</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span></code></pre>
<p>Sets the file name.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span></code></pre>
<p>This tells Style Dictionary to convert the design tokens into CSS custom properties.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Asynchronously builds the design tokens for all defined platforms. In this example, it processes the tokens and generates the <code>variables.css</code> file in the <code>build/</code> directory based on the configuration provided.</p>
<h3 id="updating-our-package.json" tabindex="-1">Updating our <code>package.json</code></h3>
<p>We can then add a <code>&quot;build&quot;: &quot;node build.js&quot;</code> to the <code>package.json</code> to allow us to use the command <code>npm run build</code> to run Style Dictionary and build out the files specified.</p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">{</span>
  <span class="token string">"name"</span><span class="token builtin class-name">:</span> <span class="token string">"style-dictionary-starter"</span>,
  <span class="token string">"version"</span><span class="token builtin class-name">:</span> <span class="token string">"0.1.0"</span>,
  <span class="token string">"type"</span><span class="token builtin class-name">:</span> <span class="token string">"module"</span>,
  <span class="token string">"scripts"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
    <span class="token string">"build"</span><span class="token builtin class-name">:</span> <span class="token string">"node build.js"</span>
  <span class="token punctuation">}</span>,
  <span class="token string">"devDependencies"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
    <span class="token string">"style-dictionary"</span><span class="token builtin class-name">:</span> <span class="token string">"^4.1.4"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="creating-some-tokens" tabindex="-1">Creating some tokens</h2>
<p>Running <code>npm run build</code> now runs the <code>build.js</code> code but we do not get a <code>variables.css</code> file in the <code>build</code> folder because we haven't created any <code>.json</code> files.</p>
<p>Here is an example to demonstrate how to structure Design tokens in <code>.json</code>.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#6c757d"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"spacing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"spacing"</span><span class="token punctuation">,</span>
    <span class="token property">"none"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"0.5rem"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"medium"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"typography"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"font"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"family"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span><span class="token punctuation">,</span>
        <span class="token property">"body"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Roboto, sans-serif"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property">"size"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontSize"</span><span class="token punctuation">,</span>
        <span class="token property">"base"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1rem"</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
        <span class="token property">"lg"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"1.25rem"</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>In this example we are defining tokens for colour, spacing and typography. Style Dictionary will traverse the file and create CSS custom properties following the tree in the <code>.json</code>.</p>
<p>You will notice that I am including a <code>$type</code> for each, or each group of tokens. Using <code>$type</code> tells Style Dictionary what kind of value it is dealing with allowing it to apply any built-in transformations (for example, a <code>color</code> token can undergo a conversion from the HEX value that is written to an RGB value if instructed to). Adding <code>$type</code> can also create consistent formatting across platforms, it can be used in validation and error handling, it can also be used if you define any custom transformations, like converting the <code>fontWeight</code> from <code>400</code> to <code>regular</code> if you needed it to.</p>
<p>When running <code>npm run build</code> which runs the <code>build.js</code> file Style Dictionary will create <code>--color-primary: #007bff;</code> from the following.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#007bff"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The full <code>variables.css</code> file will be outputted to this:</p>
<pre class="language-css"><code class="language-css"><span class="token comment">/**
 * Do not edit directly, this file was auto-generated.
 */</span>

<span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--color-primary</span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
  <span class="token property">--color-secondary</span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
  <span class="token property">--spacing-none</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
  <span class="token property">--spacing-small</span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
  <span class="token property">--spacing-medium</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--typography-font-family-body</span><span class="token punctuation">:</span> Roboto<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
  <span class="token property">--typography-font-size-base</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">--typography-font-size-lg</span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="generating-sass-variables" tabindex="-1">Generating Sass Variables</h2>
<p>Now that we have this working, we can add another platform for Style Dictionary to generate code from. Let's get it to create Sass variables in a new <code>.scss</code> file. We need to add some more code to the <code>build.js</code> to get this to work.</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">{</span>
 <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span>
 <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
 <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
   <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'_variables.scss'</span><span class="token punctuation">,</span>
   <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
 <span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>So the full <code>build.js</code> code will look like this:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> StyleDictionary <span class="token keyword">from</span> <span class="token string">'style-dictionary'</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> myStyleDictionary <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StyleDictionary</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">source</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">src/tokens/**/*.json</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token literal-property property">platforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">css</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'css'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'variables.css'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'css/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token literal-property property">scss</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">transformGroup</span><span class="token operator">:</span> <span class="token string">'scss'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">buildPath</span><span class="token operator">:</span> <span class="token string">'build/'</span><span class="token punctuation">,</span>
      <span class="token literal-property property">files</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span>
          <span class="token literal-property property">destination</span><span class="token operator">:</span> <span class="token string">'_variables.scss'</span><span class="token punctuation">,</span>
          <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'scss/variables'</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">await</span> myStyleDictionary<span class="token punctuation">.</span><span class="token function">buildAllPlatforms</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Running <code>npm run build</code> will now generate the <code>variables.css</code> file as well as a new <code>_variables.scss</code> file that will look like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// Do not edit directly, this file was auto-generated.</span>

<span class="token property"><span class="token variable">$color-primary</span></span><span class="token punctuation">:</span> #007bff<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-secondary</span></span><span class="token punctuation">:</span> #6c757d<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-none</span></span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-small</span></span><span class="token punctuation">:</span> 0.5rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$spacing-medium</span></span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-family-body</span></span><span class="token punctuation">:</span> Roboto<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-size-base</span></span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$typography-font-size-lg</span></span><span class="token punctuation">:</span> 1.25rem<span class="token punctuation">;</span></code></pre>
<h2 id="where-we're-at%2C-and-where-can-we-go-to" tabindex="-1">Where we're at, and where can we go to</h2>
<p>We have explored the basics of setting up Style Dictionary to generate CSS custom properties and Sass variables from design tokens. Covering how design tokens help maintain consistency across platforms by acting as a shared source of truth for your design decisions.</p>
<p>In automating the conversion of tokens into platform-specific formats, Style Dictionary streamlines workflows, reduces errors, and ensures that design guidelines can be implemented accurately and efficiently.</p>
<p>Using a tool like Style Dictionary to automate the process of generating styles means you can be confident that your design tokens will always be up-to-date across all platforms. It can simplify the
collaboration between designers and developers by providing a unified, consistent source of truth for visual properties, leading to a more cohesive and polished final product.</p>
<p>Now that we’ve seen how to get started with Style Dictionary, there’s much more you can explore. In future articles, we’ll dive deeper into more advanced configurations.</p>
<p>I encourage you to check out the <a href="https://v4.styledictionary.com">Style Dictionary documentation</a> to learn about its extensive capabilities. You can also explore the example code on my <a href="https://github.com/sturobson/Style-Dictionary-Starter/tree/01-Getting-Started">GitHub repository</a> to see the end results and experiment with your own setups.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>What Else Can We Do With Design Tokens?</title>
      <link href="https://www.alwaystwisted.com/articles/what-else-can-we-do-with-design-tokens.html"/>
      <updated>2024-10-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/what-else-can-we-do-with-design-tokens.html</id>
      <content type="html">
        <![CDATA[
        <p>Design Tokens are a solution in Design System that allow teams to define and use their design decisions across disciplines, codebases, and frameworks.</p>
<p>Simply put they hold a name or ‘key’ for what the design decision is called and a ‘value’ which will get generated or exposed where needed.</p>
<p>Design Tokens are generally stored in a ‘single source of truth’ where they’re defined in one place and everyone else will use that or what is exported from it to use.</p>
<p>As a front-end developer I hvae often created and stored Design Tokens in code. This is generally in a text based file format called json, but it is (or perhaps was) possible to use the more white-space strict text format yaml.</p>
<h2 id="the-design-tokens-specification" tabindex="-1">The Design Tokens Specification</h2>
<p>Before talking about what else can we do with Design Tokens, let's look at what is expected as the bare minimum. This information is taken from the work that the <a href="https://www.w3.org/community/design-tokens/">Design Tokens Working Group</a> have been working on in <a href="https://tr.designtokens.org">creating a specifcation</a> for Design Tokens.</p>
<p>As mentioned, Design Tokens are typically defined in JSON format, and the files can be named with a <code>.tokens.json</code> or <code>.tokens</code> extension.</p>
<p>Design Tokens must include a <code>$name</code> and <code>$value</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"tokenName"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#BADA55"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Design Tokens must also include a <code>$type</code>. Applying a type allows tools to interpret the tokens <code>$value</code> accordingly. You can apply the <code>$type</code> per Design Token but you can also simplify this by applying ot at a group level.</p>
<p>Example showing <code>$type</code> being applied per token:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#BADA55"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#C0FFEE"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Example showing <code>$type</code> being applied per group:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"colors"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#BADA55"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"secondary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#C0FFEE"</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Design Tokens can hold more design decisions than colour so the standard defines various token types, including <code>color</code>, <code>dimension</code>, <code>fontWeight</code>, <code>duration</code>, <code>fontFamily</code>, <code>number</code> and <code>cubicBezier</code>.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"small"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">".25rem"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"dimension"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"bold"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token number">700</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontWeight"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"slow"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"350ms"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"duration"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"mono"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"Consolas"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"fontFamily"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"line-height-normal"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token number">1.5</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"number"</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property">"easing"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"cubicBezier"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Design Tokens can also, optionally, include a description that can help explain it's purpose:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">"warning"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"$value"</span><span class="token operator">:</span> <span class="token string">"#FFF3CD"</span><span class="token punctuation">,</span>
    <span class="token property">"$type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"$description"</span><span class="token operator">:</span> <span class="token string">"Use this colour for warning states"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="can-we-do-more%3F" tabindex="-1">Can we do more?</h2>
<p>Way back in 2019 I first read about the idea of adding meta information to your design tokens <code>.json</code> objects from Christiano in their a qrticle – <a href="https://medium.com/bumble-tech/design-tokens-beyond-colors-typography-and-spacing-ad7c98f4f228">Design Tokens beyond colors, typography, and spacing</a> - the idea of meta information as part of a Design Token is also part of the proposed specification which states its use can help interoperability between tools and that we should restrict to information that is not necessarily vital to the understanding of the Design Token.</p>
<p>When I was helping Springer Nature revitalise their Design System efforts I took time to create and integrate Design Tokens into their existing code base.</p>
<p>As well as the <code>$key</code>, <code>$value</code>, and <code>$type</code> I also introduced meta information that assisted in the creating of documentation as well as specifying what syntax the tokens got generated to.</p>
<p>Below is an example of <code>json</code> that I worked on as part of the Design Tokens implementation in Springer Nature's Design System - Elements.</p>
<pre class="language-json"><code class="language-json"><span class="token property">"color"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
  <span class="token property">"primary"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"primary"</span><span class="token punctuation">,</span>
    <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"{color.brand.500}"</span><span class="token punctuation">,</span>
    <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"description"</span><span class="token operator">:</span> <span class="token string">"The primary brand colour used for the website accents"</span><span class="token punctuation">,</span>
    <span class="token property">"category"</span><span class="token operator">:</span> <span class="token string">"color"</span><span class="token punctuation">,</span>
    <span class="token property">"meta"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">"public"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token property">"deprecated"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token property">"documented"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token property">"experimental"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      <span class="token property">"SassVariable"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token property">"themeable"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
      <span class="token property">"CSSCustomProperty"</span><span class="token operator">:</span> <span class="token boolean">false</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Using this example, let's pick this apart to see what this meta information was for and how it was utilised.</p>
<h3 id="public" tabindex="-1">public</h3>
<p>This was used to show or hide certain Design Tokens, or groups of, from being displayed on the documentation site. Why -- because we were trying to have folks use the 'semantic' design decisions rather than the lower level 'raw' base layer design tokens</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">if</span> <span class="token variable">tokens</span><span class="token punctuation">.</span><span class="token variable">meta</span><span class="token punctuation">.</span><span class="token variable">public</span> <span class="token operator">%</span><span class="token punctuation">}</span>
  <span class="token operator">//</span> <span class="token variable">All</span> <span class="token variable">the</span> <span class="token variable">code</span> <span class="token keyword">for</span> <span class="token variable">documenting</span> <span class="token variable">the</span> <span class="token variable">token</span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">endif</span> <span class="token operator">%</span><span class="token punctuation">}</span></code></pre>
<h3 id="deprecated" tabindex="-1">deprecated</h3>
<p>Can be used to make your documentation site add a small 'banner' or note to the tokens documentation to state that teams should not use this going forward.</p>
<p>In nunjucks it could look something like this:</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">if</span> <span class="token variable">tokens</span><span class="token punctuation">.</span><span class="token variable">meta</span><span class="token punctuation">.</span><span class="token variable">deprecated</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token operator">=</span><span class="token string">"ds-docs-message ds-docs-message--deprecated"</span><span class="token operator">></span>
    <span class="token variable">This</span> <span class="token variable">token</span> <span class="token keyword">is</span> <span class="token test function">deprecated</span><span class="token punctuation">.</span> <span class="token variable">Please</span> <span class="token variable">update</span> <span class="token variable">to</span> <span class="token variable">the</span> <span class="token variable">latest</span> <span class="token variable">version</span><span class="token punctuation">.</span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">div</span><span class="token operator">></span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">endif</span> <span class="token operator">%</span><span class="token punctuation">}</span></code></pre>
<p>We can also set replacements with it. We can also use this when generating pre-proccesor code like Sass to include a <code>@warn</code> rule to show folks it's being deprecated.</p>
<p>In Style Dictionary we can register a new format to show the deprecation as <code>@warn</code> rule.</p>
<pre class="language-js"><code class="language-js">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'scss/deprecated-warnings'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">formatter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> dictionary<span class="token punctuation">.</span>allProperties
      <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span>
        token<span class="token punctuation">.</span>attributes<span class="token operator">?.</span>deprecated
          <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">@warn "</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'.'</span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> is deprecated. Please update it.";</span><span class="token template-punctuation string">`</span></span>
          <span class="token operator">:</span> <span class="token string">''</span>
      <span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Which would output Sass to something like this</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@warn</span> <span class="token string">"color-primary is deprecated. Please update it."</span><span class="token punctuation">;</span>
<span class="token property"><span class="token variable">$color-primary</span></span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span></code></pre>
<h3 id="experimental" tabindex="-1">experimental</h3>
<p>The initial work on moving Springer Natures Design System forward with a new version of Elements meant, at times, there would be tokens that may or may not be used in the end - this led to creating a boolean key/value pair to, again, create a 'banner' in the documentation.</p>
<p>Similar to the <code>deprecated</code> meta information - we can use something like Nunjucks to determine if the an additional message is needed if the token is experimental.</p>
<pre class="language-nunjucks"><code class="language-nunjucks"><span class="token delimiter punctuation">{%</span> <span class="token tag keyword">if</span> <span class="token variable">tokens</span><span class="token punctuation">.</span><span class="token variable">meta</span><span class="token punctuation">.</span><span class="token variable">experimental</span> <span class="token operator">%</span><span class="token punctuation">}</span>
<span class="token operator">&lt;</span><span class="token variable">div</span> <span class="token variable">class</span><span class="token operator">=</span><span class="token string">"ds-docs-message ds-docs-message--experimental"</span><span class="token operator">></span>
    <span class="token variable">This</span> <span class="token variable">token</span> <span class="token keyword">is</span> <span class="token test function">experimental</span><span class="token punctuation">.</span> <span class="token variable">Please</span> <span class="token variable">update</span> <span class="token variable">to</span> <span class="token variable">the</span> <span class="token variable">latest</span> <span class="token variable">version</span><span class="token punctuation">.</span>
<span class="token operator">&lt;</span><span class="token operator">/</span><span class="token variable">div</span><span class="token operator">></span>
<span class="token punctuation">{</span><span class="token operator">%</span> <span class="token variable">endif</span> <span class="token operator">%</span><span class="token punctuation">}</span></code></pre>
<h3 id="sassvariable" tabindex="-1">SassVariable</h3>
<p>This was used to both generate the Sass variable so that it can be used and also display the Sass variable in the documentation.</p>
<h3 id="themeable" tabindex="-1">themeable</h3>
<p>When creating code from the design tokens - this would add <code>!default</code>. This would be as part of generating the code needed, in Style Dictionary we would have a registered format similar to this.</p>
<pre class="language-js"><code class="language-js">StyleDictionary<span class="token punctuation">.</span><span class="token function">registerFormat</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'scss/themeable-defaults'</span><span class="token punctuation">,</span>
  <span class="token function-variable function">formatter</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> dictionary <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> dictionary<span class="token punctuation">.</span>allProperties
      <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">$</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'.'</span><span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>token<span class="token punctuation">.</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> token<span class="token punctuation">.</span>attributes<span class="token operator">?.</span>themeable <span class="token operator">?</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> !default;</span><span class="token template-punctuation string">`</span></span> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">;</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This would generate something like this.</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$color-primary</span></span><span class="token punctuation">:</span> #bada55 <span class="token statement keyword">!default</span><span class="token punctuation">;</span></code></pre>
<h3 id="csscustomproperty" tabindex="-1">CSSCustomProperty</h3>
<p>Similarly, this was used to generate the associated CSS custom property and also display it in the documentation</p>
<h2 id="wrapping-up" tabindex="-1">Wrapping Up</h2>
<p>Design Tokens are an essential part of Design Systems, by providing a way to develop a shared language it helps to close &quot;the gap&quot; between design and development.</p>
<p>As I have found in my consultancy work, adding layers of meta information can help with documenting, maintaining, and evolving the Design Tokens of a Design System over time.</p>
<p>Ultimately, Design Tokens can be more than storing values. They can be a way to create a cohesive, adaptable, future-proof design framework that grows with your project.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Creating Design System-Friendly Snowflakes with Utility Classes</title>
      <link href="https://www.alwaystwisted.com/articles/creating-design-system-friendly-snowflakes-with-utility-classes.html"/>
      <updated>2024-10-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/creating-design-system-friendly-snowflakes-with-utility-classes.html</id>
      <content type="html">
        <![CDATA[
        <img alt="a combined image of a screenshot of Sketch, a closer screenshot of the component, and a screenshot of some code"  src="/images/articles/snowflakes-and-tokens.jpg"/>
<p>Whilst I was helping <a href="https://www.embl.org">EMBL</a> in creating a new Design System based on a brand refresh and website re-organisation (going from 7 individual websites to one) we got to a point where other teams started to require unique components or patterns that would not necessarily fit into the larger Design System (The Visual Framework) but still needed to be ‘of the Design System’.</p>
<p>Teams needed either completely new components or they wanted to enhance or change certain characteristics of existing components to fit their unique needs.</p>
<p>I came up with a pragmatic approach that would help teams make these components whilst not venturing far away from the overall design language of the Design System.</p>
<p>In generating CSS Utility Classes from the Design Tokens it gave teams that needed to sway from the Design System the ability to create unique components (snowflakes) that were of the Design System.</p>
<h2 id="snowflakes-in-design-systems" tabindex="-1">Snowflakes in Design Systems</h2>
<p>A ’snowflake’ in a Design System is a one-off component that could be needed for a specific project, but there is an understanding that it may not be reused or may only be required by one team within an organisation.</p>
<p>These components could be problematic as part of a Design System as their intention is normally restricted to a specific use case for a certain team or brand.</p>
<p>They could potentially disrupt the overall Design System by creating the perception that it should include every component, even if a component is only intended for a specific part of a single page (or more). Instead, the Design System should primarily house components that are widely used, thoroughly tested, and essential across multiple areas.</p>
<p>To help teams still have some freedom in creating new components that they might need but it being something that may never end up in the Design System creating a solution like Design Token specific utility classes they can create these components with a level of confidence that it would match with the surrounding components from the Design System on the page.</p>
<p>When addressing the need for a team to create a unique, special, one-off snowflake I found that supplying utility classes based on the base layer and semantic layer of the Design Tokens allows them to create what they need without diverging from the look and feel of the Design System.</p>
<h2 id="utility-classes-from-design-tokens" tabindex="-1">Utility Classes from Design Tokens</h2>
<p>Utility classes can be seen as small, single-purpose CSS classes that apply specific styles directly to elements. Each utility class typically represents a single style rule or a small set of related styles, such as setting margin, padding, colour, font size, or alignment. For example:</p>
<ul>
<li><code>.u-background-color--primary</code> might apply <code>background-color: green;</code></li>
<li><code>.u-card-spacing--xl</code> could set padding to <code>2rem</code></li>
<li><code>.u-typography--button</code> might set the font family to a specific typeface for buttons</li>
</ul>
<p>Utility classes can play a vital role in enhancing flexibility within a Design System by providing a simple, consistent way to apply styles directly in the HTML. This approach can help teams adapt and create custom components (snowflakes) without the need to write new CSS each time they encounter a unique design requirement.</p>
<p>By generating these utility classes from Design Tokens, teams can be confident that any custom components they create will still align with the overall visual language of the Design System.</p>
<p>Utility classes derived directly from the Design Tokens ensure that any changes made to the tokens will automatically propagate throughout the project. This means that if a token value is updated, such as adjusting a colour or changing a spacing scale, the utility classes will reflect these changes everywhere they are used, maintaining consistency across the system.</p>
<h2 id="creating-a-snowflake-component" tabindex="-1">Creating a Snowflake Component</h2>
<p>Although the Design System that I created with EMBL had several well thought out components that were readily available their came a point where one team needed something similar to the card component. From their user tested designs they needed some extra elements as well as some different spacing and sizing because of position of this card on the page.</p>
<p>At first they wanted a whole new component that would be part of the Design System but after some back-and-forth discussions it was agreed that they would take the existing card component and adapt it using utility classes. Again, this way they can be confident that their unique 'snowflake' component will match with the rest of the page.</p>
<p>I had some time on my hands that afternoon, so I decided to see how easily it would be to augment the existing component and what utility classes would be needed to match the design.</p>
<img alt="a screenshot of the Sketch Application showing a book page with a unique sidebar design" src="/images/articles/snowflakes-sketch.jpg"/>
<p>The Sketch file in the image above was what we were working towards. There are a few components that were part of the system that we could use, the <code>figure</code> component for the book cover image, the <code>button</code> for the, um, button. There was a couple of list items and the horizontal rule but there was also some typography and spacing treatment that was specific to this 'snowflake'.</p>
<p>The image below shows this snowflake component next to the HTML that was written and adapted for it. There are additional CSS classes with <code>vf-u-</code> that denoted they were a utility class within the HTML.</p>
<img alt="a screenshot of the unique sidebar design with the related HTML next to it" src="/images/articles/snowflakes-code.jpg"/>
<p>Using utility classes along side or within existing components allowed the team to have their unique 'snowflake' component but making sure that the changes and additions applied still matched the overall Design System.</p>
<h2 id="balancing-consistency-and-flexibility" tabindex="-1">Balancing Consistency and Flexibility</h2>
<p>Utility classes can provide a flexible and efficient solution for teams who need to create unique, project-specific components without straying from the core design language. By leveraging utility classes, we can avoid the pitfalls of adding variations and unique components as a permanent part of the Design System. Instead, teams could customise existing components to suit their needs, confident that their changes would still harmonise with the Design System.</p>
<p>This approach also means that any updates to the underlying Design Tokens could be automatically reflected in these custom components.</p>
<p>It can allow for greater adaptability across different projects ensuring that even when teams needed to step outside the core Design System, they were still operating ‘of the system.’</p>
<p>Ultimately, generating utility classes from Design Tokens provided the balance between consistency and flexibility, helping EMBL create a cohesive, scalable, and user-friendly Design System.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>CSS Logical Properties, easier with Sass</title>
      <link href="https://www.alwaystwisted.com/articles/css-logical-properties-and-sass.html"/>
      <updated>2024-10-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/css-logical-properties-and-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>Using logical properties when writing CSS allows your code to adapt more naturally to various text directions and writing modes, such as left-to-right (LTR), right-to-left (RTL), or even vertical text.</p>
<p>Unlike traditional properties like <code>margin-left</code> or <code>padding-top</code>, logical properties help future-proof your designs by removing assumptions about content flow and the needs of your site visitors.</p>
<p>Rather than thinking in fixed directions, logical properties enable your designs to adapt automatically. This improves both consistency and flexibility, making your CSS more scalable and versatile for the different contexts it may encounter.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><a href="https://front-end.social/@shadeed9">Ahmad</a> has <a href="https://ishadeed.com/article/css-logical-properties/">a fantastic deep dive into CSS logical properties</a>.</p>
</div></div>
<h2 id="the-problem-with-logical-properties" tabindex="-1">The problem with logical properties</h2>
<p>They can be long, really long.</p>
<p>Whilst logical properties are a fantastic way forward offering flexibility and adaptability, they can introduce a level of verbosity that can make your code appear more cumbersome. Instead of using <code>margin-left</code>, you would need to write <code>margin-inline-start</code>, which can feel longer and less intuitive.</p>
<p>Going all in on using logical properties and as more are used, such as <code>border-block-end-width</code>, <code>border-inline-start-color</code>, the increased verbosity can make your stylesheets harder to read and potentially harder to maintain.</p>
<h2 id="let%E2%80%99s-make-things-easier-with-sass" tabindex="-1">Let’s make things easier with Sass</h2>
<p>One approach to handle the potential verbosity and cognitive load of using logical properties is to make use of the (still) widely used preprocessor, Sass. Using logical properties can feel to repetitive and could require extra thought as you translate the more traditional properties into their newer logical counterparts.</p>
<p>By using Sass with its functions, maps, variables, and mixins, you can simplify the syntax, reduce any possible mental overhead, and allow for more readable, reusable, and intuitive code that will automatically handle the complexity of logical property mapping.</p>
<h2 id="the-sass-we-need" tabindex="-1">The Sass we need</h2>
<p>When thinking about how I could use the features of Sass to make it easier to write CSS logical properties I thought about what properties to work with and what CSS values to be able to apply.</p>
<p>Although CSS logical properties go way beyond these examples, I thought It would be good to limit the amount of options to the CSS I write day-to-day that could benefit from these mixins. This boiled down to <code>margin</code>, <code>padding</code>, <code>border</code> and it’s derivatives including <code>border-radius</code> as it’s slightly different as it’s more ‘corners’ thant ‘sides.</p>
<p>I also thought that we should be able to allow the author to write in several ways which are: a raw CSS value, a Sass <code>$variable</code> (we’re using Sass after all) or a CSS custom property.
Deciding on this as ‘the brief’ I started to work on writing the code.</p>
<h3 id="a-function-for-values" tabindex="-1">A function for values</h3>
<p>In a Sass mixin, passing through a raw CSS value or Sass <code>$variable</code> is relatively straightforward but when it comes to using CSS custom properties in Sass you will eventually have to deal with interpolation. I wanted the value an author prescribes to be as less taxing as possible. I wanted an author ot be able to write</p>
<ul>
<li><code>40px</code></li>
<li><code>$padding-size-l</code></li>
<li><code>--margin-size--0</code></li>
</ul>
<p>To avoid having to write the interpolation and for the author not to have to write <code>var()</code> each time I created a small little Sass function that checks the start of the <code>$value</code>, if it contains <code>--</code> then it will return the <code>$value</code> as a CSS custom property wrapped in <code>var()</code>. If the value doesn’t contain <code>--</code> at the start it simply returns the value.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@function</span> <span class="token function">slp-process-value</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@if</span> <span class="token function">type-of</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">'string'</span> <span class="token operator">and</span> <span class="token function">str-index</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">,</span> <span class="token string">'--'</span><span class="token punctuation">)</span> <span class="token selector">==1 </span><span class="token punctuation">{</span>
    <span class="token keyword">@return</span> <span class="token function">var</span><span class="token punctuation">(</span><span class="token variable">#{$value}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span>
    <span class="token keyword">@return</span> <span class="token variable">$value</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="creating-maps-for-cleaner-mixins" tabindex="-1">Creating maps for cleaner mixins</h3>
<p>My first efforts in creating a Sass mixin had me using the <code>@if</code> and <code>@else</code> Sass control directives.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">logical-margin</span><span class="token punctuation">(</span><span class="token variable">$side</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@if</span> <span class="token selector"><span class="token variable">$side</span> == top </span><span class="token punctuation">{</span>
    <span class="token property">margin-block-start</span><span class="token punctuation">:</span> <span class="token variable">$value</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else if</span> <span class="token selector"><span class="token variable">$side</span> == bottom </span><span class="token punctuation">{</span>
    <span class="token property">margin-block-end</span><span class="token punctuation">:</span> <span class="token variable">$value</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else if</span> <span class="token selector"><span class="token variable">$side</span> == left </span><span class="token punctuation">{</span>
    <span class="token property">margin-inline-start</span><span class="token punctuation">:</span> <span class="token variable">$value</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else if</span> <span class="token selector"><span class="token variable">$side</span> == right </span><span class="token punctuation">{</span>
    <span class="token property">margin-inline-end</span><span class="token punctuation">:</span> <span class="token variable">$value</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>An author could then write:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@include</span> <span class="token function">logical-margin</span><span class="token punctuation">(</span>top<span class="token punctuation">,</span> 30px<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>which would output in a stylesheet as:</p>
<pre class="language-css"><code class="language-css"><span class="token property">margin-block-start</span><span class="token punctuation">:</span> 30px<span class="token punctuation">;</span></code></pre>
<p>Although the person authoring may never need to touch or see these mixins I think it would be cleaner, and less repetitive when writing more mixins to make use of Sass maps. We want to be able to not just port the complexity of the <code>@if</code> / <code>@else</code> statement to the Sass map but to simplify the possibilities so we can reuse the map as much as possible.</p>
<p>As we will be wanting to use these logical property Sass mixins for <code>padding</code>, <code>margin</code>, and <code>border</code> we can create a Sass map and mixins to not need those words.
Instead tying the Sass map to margin, for example:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$logical-margin-map</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">top</span><span class="token punctuation">:</span> margin-block-start<span class="token punctuation">,</span>
  <span class="token property">bottom</span><span class="token punctuation">:</span> margin-block-end<span class="token punctuation">,</span>
  <span class="token property">left</span><span class="token punctuation">:</span> margin-inline-start<span class="token punctuation">,</span>
  <span class="token property">right</span><span class="token punctuation">:</span> margin-inline-end<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We can simplify it and let the Sass mixin do some work:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$logical-map</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">top</span><span class="token punctuation">:</span> block-start<span class="token punctuation">,</span>
  <span class="token property">bottom</span><span class="token punctuation">:</span> block-end<span class="token punctuation">,</span>
  <span class="token property">left</span><span class="token punctuation">:</span> inline-start<span class="token punctuation">,</span>
  <span class="token property">right</span><span class="token punctuation">:</span> inline-end<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With the above Sass map we can reuse it in our mixins for <code>border</code>, <code>margin</code>, and <code>padding</code>.</p>
<h3 id="making-the-mixin" tabindex="-1">Making the mixin</h3>
<p>So, we have our Sass function that works out if the <code>$value</code> passed is a CSS custom property or not and we have a Sass map that helps the simplifying and tying together of traditional CSS properties and the newer logical properties. We need a mixin to put it all together.</p>
<p>So for the following examples I will concentrate on just on of the possible mixins. A Sass mixin for easier logical properties for with margin.</p>
<p>We want our Sass mixin to take two variables: the <code>$side</code> that we want the rule to change and the <code>$value</code> of how much to apply. To determine if the Sass mixin is dealing with a raw CSS value, a Sass <code>$variable</code> or a CSS custom property we want the <code>$value</code> to go through our function we have created. To determine which <code>$side</code> we want to effect and have the correct logical property printed out in CSS we need fetch that correct value from the map. Then, if the <code>$side</code> value is correct (top,bottom,left,right) we want to generate the CSS.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">logical-margin</span><span class="token punctuation">(</span><span class="token variable">$side</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$processed-value</span></span><span class="token punctuation">:</span> <span class="token function">slp-process-value</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property"><span class="token variable">$logical-side</span></span><span class="token punctuation">:</span> <span class="token function">map-get</span><span class="token punctuation">(</span><span class="token variable">$logical-map</span><span class="token punctuation">,</span> <span class="token variable">$side</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">@if</span> <span class="token selector"><span class="token variable">$logical-side</span> </span><span class="token punctuation">{</span>
    #<span class="token punctuation">{</span><span class="token string">'margin-'</span> <span class="token operator">+</span> <span class="token variable">$logical-side</span><span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token variable">#{$processed-value}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span>
    <span class="token keyword">@warn</span> <span class="token string">"Invalid side `#{$side}` specified for logical-margin mixin."</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>We would then write out similar mixins for the padding and border rules.</p>
<h3 id="using-the-mixin" tabindex="-1">Using the mixin</h3>
<p>Now we have the Sass function, map, and mixin we can then use it in our codebase:</p>
<pre><code>:root {
  --padding-l: 2rem;
}

$margin: 4rem;

body {
 @include logical-border-width(top, 1rem);
 @include logical-border-color(top, #BADA55);
 @include logical-border-style(top, solid);

 @include logical-margin(top, $margin);

 @include logical-padding(left, --padding);
 @include logical-padding(right, --padding);
}
</code></pre>
<p>Which would generate this CSS:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
  <span class="token property">--padding-l</span><span class="token punctuation">:</span> 2rem<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">body</span> <span class="token punctuation">{</span>
  <span class="token property">border-block-start-width</span><span class="token punctuation">:</span> 1rem<span class="token punctuation">;</span>
  <span class="token property">border-block-start-color</span><span class="token punctuation">:</span> #bada55<span class="token punctuation">;</span>
  <span class="token property">border-block-start-style</span><span class="token punctuation">:</span> solid<span class="token punctuation">;</span>

  <span class="token property">margin-block-start</span><span class="token punctuation">:</span> 4rem<span class="token punctuation">;</span>

  <span class="token property">padding-inline-start</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property">padding-inline-end</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--padding<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="border-radius-hits-different" tabindex="-1">border-radius hits different</h2>
<p>As I previously mentioned unlike CSS properties for rules like margin and padding that affect the sides of an element on the page <code>border-radius</code> logical properties effect the corners and because of this the syntax may seem a little odd. Rather than <code>border-top-left-radius</code> with logical properties you can write <code>border-start-start-radius</code>.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p><a href="https://front-end.social/@michelle">Michelle Barker</a> has <a href="https://css-irl.info/logical-border-radius/">a great article about logical properties and <code>border-radius</code></a> that is well worth reading.</p>
</div></div>
<p>To make use of Sass to simplify writing CSS for <code>border-radius</code> using logical properties we can still use the Sass function above, but we will need a new Sass map to accommodate the different syntax and another mixin to generate the final code.</p>
<p>For the Sass map we can write something similar to the <code>$logical-map</code> map we created earlier.</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$logical-border-radius-map</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">top-left</span><span class="token punctuation">:</span> start-start<span class="token punctuation">,</span>
  <span class="token property">top-right</span><span class="token punctuation">:</span> start-end<span class="token punctuation">,</span>
  <span class="token property">bottom-left</span><span class="token punctuation">:</span> end-start<span class="token punctuation">,</span>
  <span class="token property">bottom-right</span><span class="token punctuation">:</span> end-end<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>As the CSS for the <code>border-radius</code> is written differently to something like <code>margin</code> or <code>padding</code> we would need a new Sass mixin that accommodates this, putting the logical property between <code>border-</code> and <code>radius</code>. This is a relatively simple re-jig of the Sass mixin we have already created.</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">logical-border-radius</span><span class="token punctuation">(</span><span class="token variable">$corner</span><span class="token punctuation">,</span> <span class="token variable">$value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token property"><span class="token variable">$processed-value</span></span><span class="token punctuation">:</span> <span class="token function">slp-process-value</span><span class="token punctuation">(</span><span class="token variable">$value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token property"><span class="token variable">$logical-corner</span></span><span class="token punctuation">:</span> <span class="token function">map-get</span><span class="token punctuation">(</span><span class="token variable">$logical-border-radius-map</span><span class="token punctuation">,</span> <span class="token variable">$corner</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">@if</span> <span class="token selector"><span class="token variable">$logical-corner</span> </span><span class="token punctuation">{</span>
    #<span class="token punctuation">{</span><span class="token string">'border-'</span> <span class="token operator">+</span> <span class="token variable">$logical-corner</span> <span class="token operator">+</span> <span class="token string">'-radius'</span><span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token variable">#{$processed-value}</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span> <span class="token keyword">@else</span> <span class="token punctuation">{</span>
    <span class="token keyword">@warn</span> <span class="token string">"Invalid corner `#{$corner}` specified for logical-border-radius mixin."</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<hr>
<p>Wrapping up, I hope this post highlights how Sass can be a powerful tool for managing CSS logical properties in your everyday workflow. By leveraging Sass to handle the potential verbosity and complexity of logical properties, you can keep your codebase clean and easier to maintain, even as your designs scale and evolve. This approach simplifies the process, ensuring your CSS remains adaptable and efficient, without getting bogged down by repetitive or lengthy syntax.</p>
<p>You can start using the <a href="https://www.npmjs.com/package/sass-logical-properties">Sass Logical Properties package</a> right away, or if you’re curious about how it works, head over to the <a href="https://github.com/sturobson/sass-logical-properties">GitHub repo</a> to view the source code. With these tools, you’ll find working with logical properties far more manageable in your next project.</p>
<div class="at-c-note"><div class="at-c-note__icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -10 110 135"><path d="M72.812 78a3.124 3.124 0 0 0-3.125 3.125v4.938a3.127 3.127 0 0 1-3.125 3.124H12.5a3.13 3.13 0 0 1-3.125-3.124V13.936a3.13 3.13 0 0 1 3.125-3.124h54.062a3.127 3.127 0 0 1 3.125 3.124v14.22a3.124 3.124 0 1 0 6.25 0v-14.22c0-5.167-4.207-9.374-9.375-9.374H12.5c-5.168 0-9.375 4.207-9.375 9.375v72.124c0 5.169 4.207 9.376 9.375 9.376h54.062c5.168 0 9.375-4.208 9.375-9.376v-4.937A3.124 3.124 0 0 0 72.812 78z"/><path d="M56.523 21.309H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.124 3.124 0 1 0 0-6.25zM22.531 78.688h18.75a3.124 3.124 0 1 0 0-6.25h-18.75a3.124 3.124 0 1 0 0 6.25zM59.648 38.871a3.124 3.124 0 0 0-3.125-3.125H22.546a3.124 3.124 0 1 0 0 6.25h33.977a3.122 3.122 0 0 0 3.125-3.125zM22.547 56.438h16.988a3.124 3.124 0 1 0 0-6.25H22.547a3.124 3.124 0 1 0 0 6.25zM93.68 33.773c-4.254-4.258-11.18-4.258-15.434 0l-26.32 26.312a5.905 5.905 0 0 0-1.637 3.184l-1.441 8.53a5.916 5.916 0 0 0 1.648 5.157 5.915 5.915 0 0 0 5.157 1.645l8.527-1.442a5.9 5.9 0 0 0 3.191-1.644L93.676 49.21c4.258-4.254 4.258-11.18.004-15.438zm-30.543 37.23-8.05 1.36 1.26-7.864 18.747-18.742 6.613 6.613zm26.121-26.211-3.137 3.148-6.601-6.605 3.144-3.145a4.656 4.656 0 0 1 3.301-1.367c1.195 0 2.39.457 3.3 1.367a4.68 4.68 0 0 1-.007 6.602z"/></svg></div><div class="at-c-note__text"><p>I realise that while Sass simplifies logical properties, adding a build step isn’t always the easiest solution for everyone. However, for those already using Sass, it can help reduce complexity, improve maintainability, and enhance readability.</p>
</div></div>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>My Favourite Design Systems</title>
      <link href="https://www.alwaystwisted.com/articles/my-favourite-design-systems.html"/>
      <updated>2024-10-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/my-favourite-design-systems.html</id>
      <content type="html">
        <![CDATA[
        <p>Whether they are useful for anyone else but teams using them, or ‘masquerading’ as a marketing tool I really enjoy poring over the details of publicly available Design Systems documentation sites. Running the <a href="https://news.design.systems">Design Systems Newsletter</a> I include ones where I’ve found something new and interesting but there are always ones I go back to. I thought it would be nice to share a quick post with my all time favourites. So, in no particular order, here goes.</p>
<h2 id="nordhealth" tabindex="-1"><a href="https://nordhealth.design">Nordhealth</a></h2>
<p>Watching <a href="https://arie.ls">Arielle</a>’s work on Design Systems from <a href="https://vueds.com">VueDS</a> to <a href="https://www.duetds.com">Duets Design System</a> and now at Nordhealth. I’ve always enjoyed the attention to detail in the documentation sites. The added little features like opening up a component in CodePen. Always lovely to revisit and see what’s been updated and improved.</p>
<p><a class="at-c-link_with-image" href="<https://nordhealth.design>">
<img alt="Nord Design System Website" src="/images/articles/nord-design-system.png">
</a></p>
<h2 id="github-primer" tabindex="-1"><a href="https://primer.style">Github Primer</a></h2>
<p>I’ve been a fan of Primer since it was predominately only a CSS framework. It’s been interesting to watch it grow, become a monorepo, stop being a monorepo, and the incremental touches get added. It’s certainly helped me develop my opinions on Design Systems over the last ~10 years.</p>
<p><a class="at-c-link_with-image" href="<https://primer.style>">
<img alt="Github Primer Website" src="/images/articles/github-primer.png">
</a></p>
<h2 id="adobe-spectrum" tabindex="-1"><a href="https://spectrum.adobe.com">Adobe Spectrum</a></h2>
<p>Seeing <a href="https://www.youtube.com/watch?v=BltrdvKsrsM">a talk about Design Systems At Scale within Adobe Spectrum</a> the day they released Spectrum CSS I was instantly digging into the details. Holy-moly that was a lot of CSS custom properties.</p>
<p><a class="at-c-link_with-image" href="<https://spectrum.adobe.com>">
<img alt="Adobe Spectrum Website" src="/images/articles/adobe-spectrum.png">
</a></p>
<h2 id="atlassian-design-system" tabindex="-1"><a href="https://atlassian.design">Atlassian Design System</a></h2>
<p>Similarly to Github’s Primer, it’s been interesting to watch Atlassian evolve over time. If memory serves correct there was a period where design and development were separate websites. Now all under one domain there’s a lot of detail and interesting ways of documenting things to relish at here.</p>
<p><a class="at-c-link_with-image" href="<https://atlassian.design>">
<img alt="Atlassian Design System Website" src="/images/articles/atlassian-design-system.png">
</a></p>
<h2 id="ibm-carbon-design-system" tabindex="-1"><a href="https://carbondesignsystem.com">IBM Carbon Design System</a></h2>
<p>Again, Carbon has seen a similar evolution to others on this list. The amount of information per component is enormous with some great ideas on displaying how they can, should, and should not be used.</p>
<p><a class="at-c-link_with-image" href="<https://carbondesignsystem.com>">
<img alt="IBM Carbon Website" src="/images/articles/carbon-design-system.png">
</a></p>
<h2 id="shopify-polaris" tabindex="-1"><a href="https://polaris.shopify.com">Shopify Polaris</a></h2>
<p>Polaris was a documentation site I kept coming back to time and again when working on the Design Tokens I worked on whilst contracting at Monotype. And, again - another documentation that has evolved dramatically over time. Their Design Tokens documentation started as simply <a href="https://github.com/salesforce-ux/theo">Theo</a>’s HTML output to something grander, and more informative.</p>
<p><a class="at-c-link_with-image" href="<https://polaris.shopify.com>">
<img alt="Shopify Polaris Website" src="/images/articles/shopify-polaris.png">
</a></p>
<h2 id="other-sites" tabindex="-1">Other Sites</h2>
<p>The above are my favourites, but there are many, many more. Luckily you don’t have to continuously search the internet for them as some lovely folk in the community have created online libraries of existing Design Systems:</p>
<p><a class="at-c-link_with-image" href="<https://component.gallery>">
<img alt="Component Gallery Website" src="/images/articles/the-component-gallery.png">
</a></p>
<p><a class="at-c-link_with-image" href="<https://designsystemsrepo.com/design-systems>">
<img alt="Design Systems Repo List Website" src="/images/articles/design-systems-surf-database.png">
</a></p>
<p><a class="at-c-link_with-image" href="<https://designsystems.surf>">
<img alt="Design Systems Surf Database Website" src="/images/articles/design-systems-repo-list.png">
</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Tokens, Components, and 24Ways</title>
      <link href="https://www.alwaystwisted.com/articles/design-tokens-components-and-24ways.html"/>
      <updated>2019-12-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-tokens-components-and-24ways.html</id>
      <content type="html">
        <![CDATA[
        <p>Once again, Christmas is nearly upon us and that means it’s the time of year where there’s a fantastic new article on <a href="https://24ways.org/2019/">published on 24ways every day</a> on the lead up to Christmas Day.</p>
<p>Two years ago I was excited to write my first article for <a href="https://www.twitter.com/drewm">Drew</a> and the team where I wrote about my experimentation with <a href="https://24ways.org/2017/design-systems-and-css-grid/">CSS Grid within Design Systems</a> in my client work at the time.</p>
<p>Two years later and I’m still working with helping organisations and their Design Systems and this last year I have managed to get back into <a href="https://noti.st/sturobson">public speaking</a> after a self-imposed hiatus. The last couple of talks have been about <a href="https://www.google.com/search?client=safari&amp;rls=en&amp;q=design+tokens&amp;ie=UTF-8&amp;oe=UTF-8">Design Tokens</a> and how we can use them when creating reusable components for our Design System.</p>
<p>I felt that parts of the talk would make for a great overview of what Design tokens are, why we should look to use them, how and where we can start implementing them, and how they can help make component design more maintainable, consistent, and scaleable and empower every member of the team to make use of them.</p>
<p>I hope to expand on most of the points I have made in the article in a larger wish to try and share more in 2020.</p>
<p><a href="https://24ways.org/2019/design-tokens-and-component-based-design/">Design Tokens and Component Based Design</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Sue Andor</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-sue-andor.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-sue-andor.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>What is an expert user
<ul>
<li>part and parcel of an organisation’s operation - staff / partner / middleman</li>
<li>Have subject matter expertise</li>
<li>Use a digital interface</li>
<li>An expert user = seen as internal staff</li>
</ul>
</li>
<li>We’ve come a long way with Design Systems but not for internal staff.</li>
<li>Can’t we just use our existing Design System?
<ul>
<li>A sensible choice perhaps.</li>
<li>Saves some money.</li>
<li>But does it work?</li>
<li>Is the context design agnostic?</li>
</ul>
</li>
<li>A food delivery service has different contexts that the user and the rider need so the design should be different</li>
<li>A judge does not ‘tick boxes’ so the GDS one form element for one page does not work for the judicial service</li>
<li>How do you create a design system while developing a product
<ul>
<li>inputs are as important as outputs..</li>
<li>include research in your design system.</li>
<li>Link research to user stories within your early design system.</li>
<li>Include UX - information architecture.</li>
<li>Include UI components and elements.</li>
<li>A single source of truth for design decisions.</li>
</ul>
</li>
<li>Design for internal users improves ROI.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Siddharth Kshetrapal</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-siddharth-kshetrapal.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-siddharth-kshetrapal.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>it feels like everyone is shouting design systems and won’t stop</li>
<li>what is a design system?
<ul>
<li>way - principles and patterns.</li>
<li>how - shared and integrated.</li>
<li>why - define the overall design of a product.</li>
</ul>
</li>
<li>Design systems mean different things for different companies. It depends on the company size, culture - so yes - Bootstrap is a design system.</li>
<li>Working on the design of components allowed them to look at all the requirements of the component. The states, the tab order, the error messages. Which gave the developers all of the things they needed to implement it.</li>
<li>All products are not created equal. Building the design system for the application wasn’t made for marketing in mind. Bigger fonts, larger spacing. Design Tokens allowed to use the same components across teams more.</li>
<li>But they wanted teams to be able to ‘tweak’ the components without relying on design tokens and rebuilding the components.</li>
<li>Clean code doesn’t happen by accident.</li>
<li>Not having the time or the size of company to work on a design system, you can work on parts of it as and when. Creating a ‘system’ that helps you design a design system.</li>
<li>Like a Swiss Army knife of tools but you can’t have it all at once, so you start with a smaller, simpler knife and build up.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Shaun Bent</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-shaun-bent.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-shaun-bent.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>
<p>2006 - No designers, they made mock-ups in MS Paint.</p>
</li>
<li>
<p>2008 - Spotify released on the desktop</p>
</li>
<li>
<p>The different platforms Spotify was on were owned by different teams for those platforms</p>
</li>
<li>
<p>In 2013 Spotify decided to align all things to a single brand to address the fragmentation. It was when it started to look like the dark themed application we see today.</p>
</li>
<li>
<p>After the Design System for the new consistency was created the team creating it was disbanded.</p>
</li>
<li>
<p>In 2015 Spotify tweaked the design, including their green. With the previous team disbanded they needed to start again with GLUE. The Spotify Design System.</p>
</li>
<li>
<p>Two challenges with GLUE.</p>
<ul>
<li>Autonomy, with ‘The Spotify Model’. Having a single team created a bottleneck. One team owned the UI - teams broke away, creating their own components</li>
<li>Spotify is everywhere, Spotify changed direction to being more than just an application. Which leads to 45 individual experiences.</li>
<li>The GLUE. approach was never going to scale across 45 platforms.</li>
<li>The GLUE. had become unstuck - the decision was to close down the team. The team was disbanded but the Design System had continued usage.</li>
</ul>
</li>
<li>
<p>A team was created to solve these new problems. Creating the DLS (Design Language System).</p>
<ul>
<li>Design Tokens to the rescue! Allowed the language to go to the 45 platforms. Allowed them to make small changes that would get applied to all projects.</li>
<li>Client facing applications started to have its own Design System being created - Tape. It had massive, grassroots adoptions. Tape was open, GLUE. was closed.</li>
</ul>
</li>
<li>
<p>As it was open - Tape has become the de facto Design System for Spotify.</p>
</li>
<li>
<p>Now Spotify has 3 official design systems. But, through research they found 22 (and counting) independent Design Systems being used across Spotify.</p>
</li>
<li>
<p>Having tried Centralised and De-Centralised systems they need to find the right balance between these two options.</p>
<ul>
<li>45_+ platforms</li>
<li>22 design systems</li>
<li>~200 designers</li>
<li>~2000 developers</li>
<li>1 Spotify</li>
</ul>
</li>
<li>
<p>“Design Systems are for people” — Jina</p>
</li>
<li>
<p>Now they are creating Encore</p>
<ul>
<li>Creating a Foundation with Design Tokens</li>
<li>Web - a common base for all of Spotify’s web experiences</li>
<li>Mobile</li>
<li>Local Design Systems - tailored for specific use cases</li>
<li>Encore for X - extensible architecture. Embraces the autonomous culture.</li>
<li>Local Design Systems are built on top - but they doesn’t need to be 22 of them.</li>
<li>Each system needs to provide design, documentation and code.</li>
<li>Encore has different squads across the world. Working together.</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Miranda Garrido</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-miranda-garrido.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-miranda-garrido.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>They’ve worked with a lot of start-ups, accelerators and small companies.</li>
<li>Getting invested early means they can help in many different ways.</li>
<li>Design Systems at startups - you can over commit or they can be ignored.</li>
<li>Taking too much time in creating one rather than achieving other business goals.</li>
<li>They were asked to stop, months past and buttons, icons, colours started to stray into various sizes, looks, and hues.</li>
<li>The whole is great than the sum of its parts - Aristotle</li>
<li>How do you go about learning what a Design System is.</li>
<li>You could search the internet, find and article that will teach you … in 15 minutes.</li>
<li>You could find a similar, fully fledged Design System and apply it all for their needs. With little knowledge of what goes into it.</li>
<li>The most import thing consistency, connection, and speed in a startup.
<ul>
<li>Start with the brand - hack the consistency.
<ul>
<li>Make the brand a crucial part of your design system , because it can be a game changer.</li>
</ul>
</li>
<li>Leverage existing open source toolkits - hack for speed.
<ul>
<li>Leverage vs. Appropriation.</li>
<li>Don’t try to reinvent the wheel.</li>
</ul>
</li>
<li>It beings with you - hack for connection.
<ul>
<li>Look around, are you talking to the people next to you about it</li>
<li>Human connection is a superpower - it is the glue of your start up.</li>
</ul>
</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Lily Dart</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-lily-dart.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-lily-dart.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>At Lloyds there are 350 designers, with 9000 developers. Getting folks to use the design system is a massive effort.</li>
<li>“I tend to define the design system as the official story of how your organisation designs and build products” - Brad Frost</li>
<li>Official Culture doesn’t necessarily mean Real Culture.</li>
<li>What words would you describe your team culture when asked in an interview situation?</li>
<li>What words would you describe your team culture when asked by a friend over dinner?</li>
<li>Are the answers the same?</li>
<li>Why does the difference matter in a Design System, because you won’t talk about the things you want to do but cannot because of the real culture.</li>
<li>The gulf between reality and practice make it hard for Design Systems to land.</li>
<li>When we lust over Design Systems it’s usually from companies that have the official and real culture overlapping a lot.</li>
<li>“If the design system goes against the grain of the company, you are going to get unstuck.” – Shaun Bent</li>
<li>“As we grew and matured as a design team, our newer design clashed with the older parts” – Emily Brick, Buzzfeed</li>
<li>At Lloyds they started to build things within the existing culture of the company. It was more sharing UIKits on a server. They moved to Sketch Libraries but also found they were maintaining the components in 3 different locations.</li>
<li>They wanted to provide detailed advice in using components, rather than creating the components in yet another format.</li>
<li>How to deal with cultural mismatch:
<ul>
<li>Make intentional compromises.</li>
<li>Challenge the status quo.</li>
<li>Pick your battles, and play the long game.</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Laura González</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-laura-gonzlez.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-laura-gonzlez.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>The Guardian has a ton of layouts for different content and stories.</li>
<li>They didn’t really have a Design System and have started looking at creating one.</li>
<li>They had two subscription services needing the same pages - a great opportunity to join forces.</li>
<li>They didn’t have the resources to create a Design System, so they created a guerrilla design system.</li>
<li>Design is applying a ton of unwritten rules with writing a ton of CSS</li>
<li>Design System = Design as a System?</li>
<li>When building the subscriptions page - they could ‘copy and paste the CSS from figma’ but it doesn’t make sense, doesn’t use tokens and can easily fall apart.</li>
<li>The web is less of a garden and more of a battle ground</li>
<li>We need to make CSS is resilient and scales.</li>
<li>Design System = future-proofing - by sharing the same base core we can help the future.</li>
<li>The gaming industry are similar in they too have Design Systems for their game maps and layout.</li>
<li>How do developer a unique page as part of a system
<ul>
<li>find patterns</li>
<li>turn them into components</li>
<li>reuse, recycle, reiterate</li>
</ul>
</li>
<li>Writing more CSS is easier than talking to people.</li>
<li>If you have a website, you have a poorly documented design system already.</li>
<li>Converting the components of a page into a Storybook component library some guardian developers called it an ‘anti design system’ but it solved the goals of the subscriptions service pages.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Kathleen McMahon</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-kathleen-mcmahon.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-kathleen-mcmahon.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>
<p>A self confessed ‘dev dinosaur’ it can feel overwhelming when there seems to be a new JavaScript every week.</p>
</li>
<li>
<p>They’re part of a small team so they had to focus on small things to start with</p>
</li>
<li>
<p>Business logic out, accessibility first in.</p>
</li>
<li>
<p>You Design System is a cookbook. A cookbook has a personality.</p>
</li>
<li>
<p>Design Systems and React</p>
<ul>
<li>“React fully supports building accessible website often by using standard HTML and CSS techniques.</li>
<li>React is a utensil.</li>
<li>You are the cook. You have to know the standards of HTML, CSS, and Javascript and what you need to do to make things accessible.</li>
</ul>
</li>
<li>
<p>Creating a component is like following a receipt start with high quality ingredients - HTML</p>
</li>
<li>
<p>It is very important to create ‘guard rails’ for your components to make sure developers are always using the accessibility feature you have built in for them.</p>
</li>
<li>
<p>Buttons performa an action on a page - should look and act like a button. Screenreader support comes ‘for free’ when using a .</p>
</li>
<li>
<p>Buttons should only receive inline elements as children. A not a</p>
<p>.</p>
</li>
<li>
<p>Inputs need label and error messages. Placeholder are <strong>NOT</strong> labels.</p>
</li>
<li>
<p>Make inputs a max character count of 80. Keep labels stacked close. Labels above input, errors below input.</p>
</li>
<li>
<p>Documentation. Those massive Design Systems in public are drool-worthy.</p>
</li>
<li>
<p>In a small team you need to include the documentation that is required to start.</p>
</li>
<li>
<p>Include helpful hints into your documentation. Show people how to properly implement a component. Component Do’s and Don’ts are essential</p>
</li>
<li>
<p>Include a dedicate page to accessibility resources.</p>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Jon Reidy</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-jon-reidy.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-jon-reidy.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>HSBC is different to the average start up, it’s 150 years old.</li>
<li>No one was thinking about Design Tokens and React Components then.</li>
<li>HSBC is bg, 250,000 staff in nearly 80 countries</li>
<li>The worlds biggest international bank</li>
<li>Lots of everything which leads to lots of fragmentation.</li>
<li>HSBC has had a design system in one way or another for the lsat 9 years</li>
<li>2017 they had a rebrand that allowed a big sweeping change in creating a global digital design system.</li>
<li>The HSBC Global Digital Design System is made of:
<ul>
<li>Design Language</li>
<li>Community</li>
<li>Design Thinking</li>
<li>Review and Alignment</li>
<li>Measurement and Performance</li>
<li>Tools</li>
</ul>
</li>
<li>The HSBC Global Digital Design System is part of their “digital DNA”.</li>
<li>You need a strong community
<ul>
<li>builds trust</li>
<li>creates communication channels</li>
</ul>
</li>
<li>Creative Hierarchy was found to be important.
<ul>
<li>roles and responsibilities</li>
<li>helps create harmony</li>
<li>easier communcations</li>
<li>faster decisions made</li>
</ul>
</li>
<li>The go from a top down bottom up approach with broad decisions coming from the top and evolution of things coming from the bottom</li>
<li>Tooling is key!
<ul>
<li>Decentralised</li>
</ul>
</li>
<li>The biggest challenge they found was the ego. In large companies it’s hard to ‘make your own mark’.</li>
<li>They’re currently looking at AI and Automation for the future of their Design System.
<ul>
<li>Labour intensive tasks</li>
<li>administration</li>
<li>reports-</li>
</ul>
</li>
<li>Project: Robot Chicken
<ul>
<li>Design REviews</li>
<li>Machine Learning</li>
<li>Self Service Base</li>
<li>Takes around 8 seconds to do a AI powered design review</li>
<li>It’s currently at MVP stage, hope to be ‘ready’ in about a year.</li>
</ul>
</li>
<li>He doesn’t think it will ever take away the creative requirement of a person - but AI and automation will allow for an explosion of ideas.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - James and James</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-james-and-james.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-james-and-james.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>Design Systems are literally everywhere, and everyone seems to have one.</li>
<li>The benefits of Design Systems sounds great, but where do you start?
<ul>
<li>A design system is a continuous approach not an end solution</li>
</ul>
</li>
<li>There are two big questions to ask
<ul>
<li>Do you need a Design System?
<ul>
<li>Don’t implement one because it is a big shiny buzzword</li>
<li>Work out what are the problems you re trying to solve by introducing one</li>
</ul>
</li>
<li>Are you ready for one?
<ul>
<li>How much resource is available,</li>
<li>What buy-in do you have
<ul>
<li>The business should know the benefits</li>
<li>The business should know the constraints</li>
</ul>
</li>
<li>Having the Skills
<ul>
<li>great developers and designers</li>
<li>have documentation</li>
<li>DevOps</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Poor ownership can lead to
<ul>
<li>Disagreements over direction</li>
<li>incorrect additions</li>
<li>inconstant processes</li>
</ul>
</li>
<li>A centralised ownership created a bottleneck</li>
<li>Treat it as an open source project so everyone can help with it. This leads to better components through shared knowledge and more usage because of the shared ownership</li>
<li>But you still need a small core ownership, with a design system council
<ul>
<li>They have key responsibilities.
<ul>
<li>updates</li>
<li>roadmap</li>
<li>identify inconsistencies</li>
</ul>
</li>
</ul>
</li>
<li>Why Design Reviews?
<ul>
<li>Where should the component be built?</li>
<li>Are there existing components?</li>
<li>More than one team that need similar components</li>
</ul>
</li>
<li>Hold Knowledge sharing sessions.
<ul>
<li>What we wish we’d known
<ul>
<li>Ensure organisational understanding</li>
<li>understand impact</li>
<li>understand bottlenecks of centralised teams</li>
</ul>
</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Bernardo Raposo</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-bernardo-raposo.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-bernardo-raposo.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>“Design Systems are 80-90% people stuff, 10-20% design/dev/tools stuff.” – Brad Frost</li>
<li>“A Design System is a language. If people are not speaking the same language, there will be nothing but confusion” – Alex</li>
<li>Design System is the documentation.</li>
<li>The Apple Human Interface Guidelines that is 35 years old”
<ul>
<li>General design principles</li>
<li>Principles of graphic communicatoin</li>
<li>A strategy for programming</li>
<li>Designing for disabled people</li>
<li>elements of the Desktop interface</li>
</ul>
</li>
<li>Design System is the code.</li>
<li>What about Code in design tools - <a href="https://airbnb.design/painting-with-code">Paint With Code</a></li>
<li>Design Is Code.</li>
<li><a href="https://www.github.com/seek-oss/playroom">Playroom</a></li>
<li>Design System Relationships are based on trust and being present.</li>
<li>Make Design Systems more open.</li>
<li>Make Design Systems more human.</li>
<li>We need different tools for this relationship between Designers and Developers
<ul>
<li>Interplay</li>
<li>Alva</li>
<li>UXPin Merge</li>
<li>Framer X</li>
<li>Builder X</li>
<li>Modulz</li>
</ul>
</li>
<li>Design System is the language.
<ul>
<li>Should we create a common format for design systems</li>
<li><a href="http://Diez.org">Diez.org</a></li>
<li>Storybook CSF</li>
<li>Avocode SDK</li>
</ul>
</li>
<li>Use the documentation as a starting point.</li>
<li>Add code to improve the design process.</li>
<li>Think about the people using the Design System.</li>
<li>Make Design open to everyone.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems London 2019 - Anja Klüver</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-london-2019-anja-klver.html"/>
      <updated>2019-11-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-london-2019-anja-klver.html</id>
      <content type="html">
        <![CDATA[
        <ul>
<li>Everything they work on has to be measurable, including the Design System.</li>
<li>The business case for the design system needs to be addressed.</li>
<li>to make sure the company adopt it, as it’s an organisational transform and change.</li>
<li>The need for a Design System is a need for efficiency of scale.</li>
<li>As products become more complex over time there is a curve where static things will suffer and there’s a need for more easy-to-update things from a Design System.</li>
<li>Selling a Design System – “A successful design system delivers cohesive, scaleable features in a way that’s efficient for both design and development”.</li>
<li>What is the economic impact of using a Design System. Design generates ROI - for IBM it saved them $20.6m and reduced the risk cost by $18.6m.</li>
<li>A client they have been worked with they had to go through three levels of management to discuss the business needs for a Design System.
<ul>
<li>30% cash saving.</li>
<li>10-30% increase in conversion.</li>
<li>10-30% increate in customer loyalty.</li>
</ul>
</li>
<li>Legacy development was often in a ‘waterfall’ with a Design System you save time to market and cost because of the agile process that is indicative of creating one.</li>
<li>A Design System allows for triggering innovation, faster prototyping, increased usability and adoption, and brand perception.</li>
<li>How to measure?
<ul>
<li>There’s ‘quant’ - time and resource costs, the rework and repetition, the tech. and design debt. There’s also time to market, scalability, adoption and loyalty.</li>
<li>There’s ‘qual’ - brand equity, innovation, brand perception, team happiness, client NPS score.</li>
</ul>
</li>
<li>Peoples Adoption Hurdles with starting a Design System:
<ul>
<li>culture and behaviour.</li>
<li>social-technical.</li>
<li>totalitarian and inflexible.</li>
<li>exploration and divergence.</li>
</ul>
</li>
<li>You need to deliver measured benefits step–by–step to keep up with adoption
<ul>
<li>Make it user first.</li>
<li>Start small.</li>
<li>Make sure the team is empowered and there’s a consent to the system.</li>
<li>Demo the benefits</li>
<li>Manage the perceptions</li>
<li>Make sure it has shared ownership</li>
</ul>
</li>
<li>Four principles for a design system
<ul>
<li>Inspire and Inform - start with a pilot project, a new project</li>
<li>Create - Bring methodology alive, show and tell.</li>
<li>Consult and Educate - adoption workshops</li>
<li>Collaborate and Manage - embed and define the governance.</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Creating Utility Classes with Design Tokens using Sass</title>
      <link href="https://www.alwaystwisted.com/articles/creating-utility-classes-with-design-tokens-using-sass.html"/>
      <updated>2019-07-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/creating-utility-classes-with-design-tokens-using-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>At the start of a Design System, there’s a chance that things can move pretty fast.</p>
<p>There may be more than one or two people working on creating components (if you’re lucky). You might want to prototype things quickly with “throwaway code”. When it matures there may be certain use cases where you need a slight adjustment here and there for a particular component to work, or you may not be able to include the components you need as you would hope to.</p>
<p>After creating a set of <a href="https://css-tricks.com/what-are-design-tokens/">Design Tokens</a> for my clients Design System I looked at how best we can quickly create some additional utility classes for the various &quot;exceptions to the rule&quot; mentioned above. We needed something that would work automatically, programmatically, and with as little human interaction as possible once it was set up.</p>
<h2 id="using-sass-in-2019" tabindex="-1">Using Sass in 2019</h2>
<p>The project was already using Sass (a decision that was made after some research (that might be another article, whenever I find the time)) and I have <a href="2014-03-06-even-better-each-loops-with-sass-33.html">previously used loops</a> and <a href="https://sass-lang.com/documentation/interpolation">interpolation</a> so I knew we could create these classes with a pre-processor language that is already in place without resorting to something else, an extra dependency.</p>
<p>As we’re using Sass already we are outputting the Design Tokens using <a href="https://github.com/salesforce-ux/theo">Theo</a> to generate files of Sass <a href="https://sass-lang.com/documentation/variables">variables</a> and <a href="https://sass-lang.com/documentation/values/maps">maps</a> that are needed.</p>
<p>To create our utility classes we would need a Sass <a href="https://sass-lang.com/documentation/at-rules/mixin">@mixin</a> that would use the class selector to inform the initial naming of the created rule sets. An <a href="https://sass-lang.com/documentation/at-rules/control/each">@each rule</a> to loop through the Sass maps, and an additional <code>$prefix</code> variable to allow us to create classnames.</p>
<h2 id="design-tokens-and-maps" tabindex="-1">Design Tokens and Maps</h2>
<p><a href="https://github.com/salesforce-ux/theo">Theo</a> takes your Design Tokens that can be authored in a <code>.yml</code> or <code>.json</code> format and then can convert them into a Sass map, amongst a lot of other formats.</p>
<p>An example Sass map that we are going to use could look something like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token property"><span class="token variable">$ds-color-map</span></span><span class="token punctuation">:</span> <span class="token punctuation">(</span>
  <span class="token property">green-100</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">,</span>
  <span class="token property">green-200</span><span class="token punctuation">:</span> #a5d6a7<span class="token punctuation">,</span>
  <span class="token property">green-300</span><span class="token punctuation">:</span> #81c784<span class="token punctuation">,</span>
  <span class="token property">green-400</span><span class="token punctuation">:</span> #66bb6a<span class="token punctuation">,</span>
  <span class="token property">green-500</span><span class="token punctuation">:</span> #4caf50<span class="token punctuation">,</span>
  <span class="token property">green-600</span><span class="token punctuation">:</span> #43a047<span class="token punctuation">,</span>
  <span class="token property">green-700</span><span class="token punctuation">:</span> #388e3c<span class="token punctuation">,</span>
  <span class="token property">green-800</span><span class="token punctuation">:</span> #2e7d32<span class="token punctuation">,</span>
  <span class="token property">green-900</span><span class="token punctuation">:</span> #1b5e20<span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2 id="creating-the-%40each-loop" tabindex="-1">Creating the @each loop</h2>
<p>In the above map with have the key/value pair of the name of the colour and the hex code that represents it. To create an <code>@each</code> rule we would need to write something like:</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.u-color </span><span class="token punctuation">{</span>
  <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$name</span>, <span class="token variable">$hex</span> in <span class="token variable">$ds-colors-map</span> </span><span class="token punctuation">{</span>
    <span class="token property"><span class="token variable">#{$name}</span></span><span class="token punctuation">:</span> <span class="token variable">$hex</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Using the <code>@each</code> rule we go through key/value pairs of <code>$ds-colors-map</code> and get the key: <code>$name</code> and the value: <code>$hex</code>. We then use these variables to create the declaration inside the rule. This <code>@each</code> rule makes use of interpolation to turn the <code>$name</code> variable into property inside the declaration.</p>
<p>But this would only create a list of CSS colour rules within the ruleset like:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.u-color</span> <span class="token punctuation">{</span>
  <span class="token property">green-100</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
  <span class="token property">green-200</span><span class="token punctuation">:</span> #a5d6a7<span class="token punctuation">;</span>
  <span class="token property">green-300</span><span class="token punctuation">:</span> #81c784<span class="token punctuation">;</span>
  <span class="token property">green-400</span><span class="token punctuation">:</span> #66bb6a<span class="token punctuation">;</span>
  <span class="token property">green-500</span><span class="token punctuation">:</span> #4caf50<span class="token punctuation">;</span>
  <span class="token property">green-600</span><span class="token punctuation">:</span> #43a047<span class="token punctuation">;</span>
  <span class="token property">green-700</span><span class="token punctuation">:</span> #388e3c<span class="token punctuation">;</span>
  <span class="token property">green-800</span><span class="token punctuation">:</span> #2e7d32<span class="token punctuation">;</span>
  <span class="token property">green-900</span><span class="token punctuation">:</span> #1b5e20<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>What we want is to generate individual class selectors to hold each key/value pair.</p>
<h2 id="making-the-%40mixin" tabindex="-1">Making the @mixin</h2>
<p>To get Sass to generate the utility classes for our Design Tokens using the Sass maps. We need to create a <code>@mixin</code> and slightly change the <code>@each</code> rule. Before we look into that we should think about the structure of the class selectors we are wanting to create. Using colour as the example I want to create a set of CSS rules that look like this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.u-color-text-green-100</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>With a <code>@mixin</code> we need to be able to create part of the <code>selector</code> of a rule so that it include <code>--</code>. We also need the correct key: <code>$name</code> as part of the <code>selector</code>, and value: <code>$hex</code> as the declarations <code>value</code>.</p>
<p>We can make use of Sass’ interpolation to help us with this, so that we can generate the correct naming conventions for the class selectors. Inside the <code>@mixin</code> we can add our working <code>@each</code> rule like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token selector">color-utilities </span><span class="token punctuation">{</span>
  <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$name</span>, <span class="token variable">$hex</span> in <span class="token variable">$ds-colors-map</span> </span><span class="token punctuation">{</span>
    <span class="token selector"><span class="token parent important">&amp;</span>-<span class="token variable">#{$name}</span> </span><span class="token punctuation">{</span>
      <span class="token property">color</span><span class="token punctuation">:</span> <span class="token variable">$hex</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>When called this <code>@mixin</code> will go through the <code>$ds-colors-map</code> we have and generate a class selector using the parent selector name using the <code>&amp;</code>, we add the <code>--</code> to then separate the parent selector from the key: <code>$name</code> of the pair in the map and then print the value: <code>$hex</code> as the value in the declaration. When invoked in a class like:</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.u-color-text </span><span class="token punctuation">{</span>
  <span class="token keyword">@include</span> <span class="token function">color-utilties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>We get an compiled output like:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.u-color-text-green-100</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-200</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #a5d6a7<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-300</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #81c784<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-400</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #66bb6a<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-500</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #4caf50<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-600</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #43a047<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-700</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #388e3c<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-800</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #2e7d32<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-text-green-900</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #1b5e20<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="extending-the-%40mixin" tabindex="-1">Extending the @mixin</h2>
<p>That works great but it’s not very flexible. I want to generate rules for each way colour can be used in CSS. Not only for text but for borders and backgrounds like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token comment">// text colours</span>
<span class="token selector">.u-color-text-green-100 </span><span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// background colours</span>
<span class="token selector">.u-color-background-green-100 </span><span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// border colours</span>
<span class="token selector">.u-color-border-green-100 </span><span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>To do this we can modify the <code>@mixin</code> we have created to allow us to set the <code>property</code> that would be inside the declaration. We need to add an argument to our <code>@mixin</code> that will set this property and then use that argument where needed. As it’s the <code>property</code> of the declaration that is needs to be changed we can add a it to our <code>@mixin</code> along with a default so the first line is like:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">color-utilities</span><span class="token punctuation">(</span><span class="token property"><span class="token variable">$property</span></span><span class="token punctuation">:</span> <span class="token string">'color'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></code></pre>
<p>We then need to use that <code>$property</code> argument as our property in the declaration using interpolation, so that the whole <code>@mixin</code> looks like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token keyword">@mixin</span> <span class="token function">color-utilities</span><span class="token punctuation">(</span><span class="token property"><span class="token variable">$property</span></span><span class="token punctuation">:</span> <span class="token string">'color'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">@each</span> <span class="token selector"><span class="token variable">$name</span>, <span class="token variable">$hex</span> in <span class="token variable">$vf-colors-map</span> </span><span class="token punctuation">{</span>
    <span class="token selector"><span class="token parent important">&amp;</span>-<span class="token variable">#{$name}</span> </span><span class="token punctuation">{</span>
      <span class="token property"><span class="token variable">#{$property}</span></span><span class="token punctuation">:</span> <span class="token variable">$hex</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Doing this allows us to include the <code>@mixin</code> in the 3 types of colour classes we want to create:</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.u-color-text </span><span class="token punctuation">{</span>
  <span class="token keyword">@include</span> <span class="token function">color-modifiers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-background </span><span class="token punctuation">{</span>
  <span class="token keyword">@include</span> <span class="token function">color-modifiers</span><span class="token punctuation">(</span>background-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.u-color-border </span><span class="token punctuation">{</span>
  <span class="token keyword">@include</span> <span class="token function">color-modifiers</span><span class="token punctuation">(</span>border-color<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Which will generate the a list of rules like I have mentioned above.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.u-color-text-green-100</span> <span class="token punctuation">{</span>
  <span class="token property">color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.u-color-background-green-100</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">.u-color-border-green-100</span> <span class="token punctuation">{</span>
  <span class="token property">border-color</span><span class="token punctuation">:</span> #c8e6c9<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="what-next%3F" tabindex="-1">What next?</h2>
<p>Now we can create an individual rule for each of the colours that our Design Tokens has for text, background and border but Design Tokens are more than colour. With a few modifications to the <code>@mixin</code> created here we can then do this with any typographic styles and spacing values we have.</p>
<p>I created a CodePen that includes the <code>@mixins</code> that can be used to create those additional utility classes.</p>
<p>See the Pen <a href="https://codepen.io/sturobson/pen/oKXBxL/">Utility Class Sass Generators</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>) on <a href="https://codepen.io">CodePen</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Curating A Design System Newsletter</title>
      <link href="https://www.alwaystwisted.com/articles/curating-a-design-system-newsletter.html"/>
      <updated>2019-07-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/curating-a-design-system-newsletter.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="this-ain%E2%80%99t-my-first-rodeo." tabindex="-1">This ain’t my first rodeo.</h2>
<p>For a couple of years I ran an email newsletter for all things Sass, creating a weekly newsletter sharing articles, tutorials, code, videos, pretty much anything I found interesting about Sass.</p>
<p>Giving myself the task of sending this out weekly though had three things to it’s detriment.</p>
<p>The first was having to find 8-10 links per week. Often I would be adding items to make up the numbers and this led to several similar items and sometimes subpar items being included.</p>
<p>The second was adding the items. I was using Mailchimp with a custom design for the newsletter. I would bookmark the items as I went through my week and then copy and paste them into the relevant HTML snippets and adding a blurb about the item before the newsletter hit the inboxes.</p>
<p>The third was my health. Forcing myself on a release date and time of every Tuesday at 10am made me have to continually do the legwork to get it released.</p>
<p>The third one was where I just gave up. I stopped completely.</p>
<p>Roll on a couple of years and I started working on more projects that were wholly related to what’s now often termed “Design Systems”.</p>
<p>I was reading everything I could find about the myriad of things that make up a “Design System” and got to a point where I felt I should start sharing these.</p>
<p>I should start a new newsletter.</p>
<h2 id="adding-constraints" tabindex="-1">Adding Constraints</h2>
<p>Knowing what happened the first time I decided to run a newsletter I gave myself some constraints:</p>
<h3 id="curated" tabindex="-1">Curated</h3>
<p>As I’ve mentioned at some points I was adding items to the Sass News email just to fill the space. This time around I decided I would only add things I felt others would benefit from and things that offered something new to the conversation. I didn’t want to include the 40th article on “What is a Design System”.</p>
<p>I still read through these, if they didn’t add anything substantial to the conversation they didn’t get into the email.</p>
<h3 id="sporadic-by-nature" tabindex="-1">Sporadic by nature</h3>
<p>I didn’t want to tie it down to a weekly publication cycle and by going with the ‘curated’ idea on what is included I allowed myself to decide when to ‘hit publish’. When I felt it was ready, not when it was 10am on an given Tuesday.</p>
<h3 id="no-blurbs" tabindex="-1">No blurbs</h3>
<p>Sometimes the titles of items don’t really give to much away and this could stop people clicking, but with the two constraints above affecting what goes in it was also my time being saved.</p>
<h2 id="where-am-i-looking%3F" tabindex="-1">Where am I looking?</h2>
<p>To make a (what I hope to be) useful newsletter I read, watch, listen to a plethora of resources on Design Systems almost everyday, but where do they come from?</p>
<h3 id="rss" tabindex="-1">RSS</h3>
<p>I have an RSS feed that not only subscribes to several people, companies and ‘magazines’ int the industry pulls in feeds from Medium for:</p>
<ul>
<li>Design Systems</li>
<li>Pattern Libraries</li>
<li>Styleguides</li>
<li>Documentation</li>
</ul>
<p>Sometimes the Medium RSS feeds are chock-full of things, and I am seeing an increase in this as the weeks go on.</p>
<p>To note, if I find something via a Medium RSS feed and find that the author has posted it on their own blog, I link to that instead.</p>
<h3 id="twitter" tabindex="-1">Twitter</h3>
<p>I have several saved searches that I look through a couple of times a day, these are the same terms as the list of RSS feeds from Medium.</p>
<h3 id="google" tabindex="-1">Google</h3>
<p>I search for “Design Systems” in Googles search engine, picking the last week, or last 24 hours (depending on how long I think it was when I did it last. This search is also used in the Google Search video section.</p>
<h2 id="about-that-emoji" tabindex="-1">About that emoji</h2>
<p>Essentially the icons (kind of) relate to the sections: articles, tools and tutorials interesting reads with things like slide decks, videos, and podcasts having their own emojis. Leaving a heart for actual design systems I have found.</p>
<p>There’s really nothing more to the use of emoji than that. Initially I went with no categories at all, but felt they would help people clicking on what is just the title. I hope adding a emoji used helps playfully inform readers that they’re about to click on a video rather than an article.</p>
<p>Those Warning Signs</p>
<hr>
<p>Some time ago I was going through the backlog of around 90 unread articles on Design Systems. About 80 of those were Medium articles and about 40 of those took me to either their user-hostile “you ready a lot and we like that” pop-up or their money-grabbing “you’ve read lots this month, pay us to read some more.”, it turns out that Medium only likes you reading things when you give money to do so.</p>
<p>Therefore I’ve started to add a little warning notice to each article that’s on Medium. There are people that probably won’t click on it, but there are people that will (and do) and I just want to let them know they might actually be able to read it.</p>
<p>If I ever find an article that has been syndicated to Medium where, generally, the writer publicises the original url I use that (note: with the various Medium pop-ups it is better to put that link at the top of your article).</p>
<p>I know some people might feel begrudged with this, “why shouldn’t I expect to get some income from what I share?”, I don’t begrudge you from wanting to make a little bit (I assume it’s a little bit) of money from your efforts. I just do not like Medium’s hostile environment for the reader.</p>
<h2 id="what-does-that-summary-line-mean%3F" tabindex="-1">What does that summary line mean?</h2>
<p>From “…the room was humming harder, as the ceiling flew away.” to “For you there might be another star, but through my eyes the light of you it’s all I see.” every issue of the newsletter gains a unique summary. As part of publishing a newsletter using <a href="https://www.curated.co">curated</a> you have to provide a summary text as well as a title. So I’ve borrowed a concept I think I first saw on either Raw! or Total Guitar.</p>
<p>Every time I come to hit the publish button, I now look to the last song that I was listening to on Spotify, pick a line or two from the lyrics and use that as the summary.</p>
<h2 id="if-it%E2%80%99s-curated%2C-isn%E2%80%99t-it-biased%3F" tabindex="-1">If it’s curated, isn’t it biased?</h2>
<p>Maybe, I hope it isn’t. I try and include things that I really think others would benefit from rather than “what’s hot on twitter” in the design systems spectrum.</p>
<p>I hope through the various sources I find articles exposes articles that others may miss, or never see. I am reading several “What is a Design System?” posts a week so you don’t really have to. If I feel an article has something new, unique, or different to share. That’s a surefire way of it being added into the newsletter.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Varya Stepanova</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-varya-stepanova.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-varya-stepanova.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="a-practical-guide-to-building-your-design-system-infrastructure" tabindex="-1">A practical guide to building your design system infrastructure</h2>
<p>In <a href="https://twitter.com/varya_en">Varya’s</a> talk for Patterns Day 2019 they discussed a practical way of applying technologies like React with your design system.</p>
<h3 id="design-system-at-elisa" tabindex="-1">Design System at Elisa</h3>
<ul>
<li>Library of css components</li>
<li>Libraries of React components</li>
<li>UI kit in Sketch</li>
<li>Shared tools and practices</li>
<li>Great design community</li>
<li>World-class front-end teams</li>
</ul>
<h3 id="what-is-design-systems%3F" tabindex="-1">What is Design Systems?</h3>
<p>Often it is termed as purely component libraries, for Varya it means:</p>
<ul>
<li>shared practices (like component libraries and documentation).</li>
<li>tools (for developers and designers to keep a standardised design system).</li>
<li>processes.</li>
<li>community.</li>
</ul>
<h3 id="to-react-or-not-react%3F" tabindex="-1">To React or Not React?</h3>
<ul>
<li>React Styleguidist and Storybook are seen as things for React Libraries, great tools that can have a component playground and also be used as a documentation site.</li>
<li>Yet, they can also be used for not just React.</li>
<li>With Styleguidist, you can create the component by adding the HTML in a markdown file for the component.</li>
<li><a href="https://twitter.com/alexmuench/status/1111297292215246850">Alex</a></li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Una Kravets</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-una-kravets.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-una-kravets.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="the-problem-with-legos-%26-system-at-scale" tabindex="-1">The Problem With Legos &amp; System at Scale</h2>
<p>In <a href="https://twitter.com/una">Una’s</a> talk they discussed how Design Systems can fail and what we can do to stop that.</p>
<ul>
<li>Design Systems Support User Needs</li>
<li>But not all design systems are successful</li>
<li>Reasons why Design Systems fail</li>
<li>These five elements are really key:
<ul>
<li>Investment - small, incremental, continuous change is necessary for a design system to succeed as a a product grows and adapts.</li>
<li>Communication - creating continuous and open dialog between designers developers, project mangaers and end-users.</li>
<li>Buy-In - A system needs support to succeed.</li>
<li>Solid Architecture - What happens when nobody is using today’s frameworks anymore? What’s the next thing?</li>
<li>Frictionless - If a system is more difficult to use than the current workflow, nobody will want to adopt it.</li>
</ul>
</li>
<li>Building a design system is like building with lego blocks.</li>
<li>When you really start to scale the system - the lego analogy breaks down.</li>
<li>Lego has custom pieces doing one thing and that one thing really well.</li>
<li>With Lego sets you cannot build a T-Rex lego set with a car lego set.</li>
<li>A Lego set will never change.</li>
<li>You could use a part from a different set, but it would look odd.</li>
</ul>
<h3 id="design-is-ever-changing." tabindex="-1">Design is ever-changing.</h3>
<ul>
<li>
<p>Designs change.</p>
</li>
<li>
<p>You need to write the CSS for the new trends.</p>
</li>
<li>
<p>We moved from skeuomorphism to flat design using the technology available to create the designs.</p>
</li>
<li>
<p>Typography changes, the system needs to keep up</p>
</li>
<li>
<p>Form Follows Function</p>
</li>
<li>
<p>Design Follows Technology</p>
</li>
</ul>
<p>Just as design changes, design systems technology changes. Which is great, but can also be a challenge to how your Design System scales.</p>
<ul>
<li>A Unified Design Spec
<ul>
<li>guidelines, guidelines, guidelines</li>
<li>in Material each component has specific guidelines as well as generic guidelines.</li>
<li>It’s nice to have robust documentation, but you need the tooling to work with the spec.</li>
</ul>
</li>
<li>Tooling
<ul>
<li>a colour picker on Material allows you to define a theme across your product</li>
<li>a shape tool allows you to define the borders on all relevant components.</li>
<li>Google Fonts - an excellent resource of free typefaces</li>
<li>With the tooling in place you can move to components</li>
</ul>
</li>
<li>Components
<ul>
<li>Material provides components you can use within your material project or individually.</li>
</ul>
</li>
<li>Theming
<ul>
<li>Material provides the flexibility for brands to maintain their style on top of the components from Material, so everything doesn’t ‘just look like Google’.</li>
</ul>
</li>
</ul>
<p>In the end the design team found three sub-systems for theming that help build systematic expression of your product</p>
<ul>
<li>Typography</li>
<li>Colour</li>
<li>Shapes</li>
</ul>
<p>Colour:</p>
<ul>
<li>colour effects text and background of your application</li>
<li>primary and secondary colours</li>
<li>Allocate semantic meaning to your core application.</li>
<li>With the Sass variables or CSS custom properties you can easily see the difference in the components.</li>
</ul>
<p>Typography:</p>
<ul>
<li>think about the shape of the type you’re using</li>
<li>can be easily imported via Sass.</li>
</ul>
<p>Shape:</p>
<ul>
<li>strong difference in shape can be used to direct attention.</li>
<li>asymmetric shapes can help emphasise certain aspect of the UI</li>
<li>shape can be used to communicate a component state.</li>
<li>CSS Houdini allows you to tell the browser how it should read your CSS via JavaScript.</li>
<li>Houdini allows you to create shapes that are not in the CSS spec (yet).</li>
</ul>
<h3 id="overrides" tabindex="-1">Overrides</h3>
<ul>
<li>nobody needs a custom component</li>
<li>… everybody needs a custom component.</li>
<li>When we provide theming, some times what is available is not enough.</li>
<li>In Material you can use Sass mixins to override the CSS</li>
</ul>
<blockquote>
<p>CSS is Not the Enemy.</p>
</blockquote>
<p><a href="http://glitch.com/~material-theme-builder">Material Theme Builder</a>.</p>
<p>When building your own themes using Material keep in mind accessibility, colour contrast is on you to get right.</p>
<p>If we stifle the needs of users, the design system will not be used.</p>
<p>Material, like any component library is a work in progress.</p>
<p>Design Systems are way to complex to keep comparing them to Lego.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Inayaili de León</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-inayaili-de-len.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-inayaili-de-len.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="5-untruths-about-design-systems" tabindex="-1">5 untruths about design systems</h2>
<p>In their presentation at Patterns Day 2019, <a href="https://www.twitter.com/yaili">Yaili</a> talked about the untrue truths around Design Systems.</p>
<ul>
<li>
<p>Worked on Design Systems for both product and within agencies.</p>
</li>
<li>
<p>Has seen the mistakes that have been made.</p>
</li>
<li>
<p>When people talk about Design Systems - they often talk about the beautiful public sites available.</p>
</li>
<li>
<p>Then you see blogposts, podcasts, videos telling us how they figured things out</p>
</li>
<li>
<p>Then we look at our design systems and see the mess.</p>
</li>
<li>
<p>What you see in a public design system is a facade.</p>
</li>
<li>
<p>In reality, things are ugly, unfinished with tape and gum holding things together.</p>
<p>You’re not alone in having an imperfect system with documentation people don’t follow, with people ignoring the system exists altogether. No-one has it all figured out. No-one.</p>
<h3 id="untruth-%231" tabindex="-1">Untruth #1</h3>
<p>“Everyone loves and understands our work.”</p>
<p>“Some people hate us, and many don’t know what we’re trying to do.”</p>
<p>By explaining it to others in the company as “Do you know Google’s Material UI” doesn’t work.</p>
<p>What works is to sell the system, adapting to the different needs and requirements of the different teams in the company. How things would change, and what would get easier when you use the Design System.</p>
<p>You want to get from “Why am I wasting my time on this?” to “When can I start to use it?</p>
<h3 id="untruth-%232" tabindex="-1">Untruth #2</h3>
<p>“Our documentation is always up to date.”</p>
<p>“We don’t always have the time to document things.”</p>
<ul>
<li>When you look at the ‘faced’ you can see things like the nice grids, icons, and typography.</li>
<li>The truth is there are a lot of components that are used on sites now that are not documented and some that you may not even know about.</li>
<li>Working on a Design System is like a train that never reaches its destination. It just stops once in a while.</li>
<li>There is work we know that needs to be done, but nobody is asking for it.</li>
<li>Make time to improve things bit by bit.
<ul>
<li>Decide on a holistic structure.</li>
<li>A documentation page structure could have: Examples, Usage, Anatomy, Developer Guidance, API.</li>
</ul>
</li>
</ul>
<h3 id="untruth-%233" tabindex="-1">Untruth #3</h3>
<p>“Everyone works together in harmony.”</p>
<p>“We block each other all the time.”</p>
<ul>
<li>This does not just the members of the Design Systems team.</li>
<li>People will go ahead and just build something that matches their needs</li>
<li>You need to work on if patterns being created are new, or can be extended from existing components.</li>
<li>We shouldn’t block people from using the system, but should have process in place to improve the system.</li>
<li>You need to be comfortable in the knowledge that a Design Systems team will work slower than a ‘features’ team.</li>
</ul>
<h3 id="untruth-%234" tabindex="-1">Untruth #4</h3>
<p>“no one ever needs custom components”</p>
<p>“someone needs a custom component every day”</p>
<ul>
<li>It can be considered too soon to add a new component.</li>
<li>There might not be the time to create a shared solution</li>
<li>“I would like it if no-one asked for a new component”</li>
<li>The relationship between a product and a design system team is like a ‘push and pull’</li>
<li>If the product didn’t try new things, it would eventually become stale.</li>
<li>But if every change was accepted, you would be in a mess.</li>
<li>Make new things, think outside the box but be in the knowledge that it might not actually change what is within the design system</li>
</ul>
<p>It’s a balancing act. If all you do is accept all the proposals, you’re not doing a good job of maintaining a solid foundation in a Design System. The quality of work is going to suffer. If you say no to every request for change. People will just stop coming to the Design System. They will think that no-one is listening and that it is not for them.</p>
<p>Each new request needs to be within the context of the system.</p>
<h3 id="untruth-%235" tabindex="-1">Untruth #5</h3>
<p>“We validate everything.”</p>
<p>“Most times we push to the system without testing.”</p>
<ul>
<li>Sometimes there is not the time to get things through the entire process of testing, auditing, etc.</li>
<li>This goes back to being slow with the Design System.</li>
<li>You need to have conversations about what you’re working on</li>
<li>You need to build it</li>
<li>You need to continually improve it</li>
<li>You need to document it</li>
<li>You need to test it</li>
<li>Think of ways you can get other people to help with this process to validate things.</li>
<li>How can we make this true?
<ul>
<li>make a rule that a component is 100% valid until it has user-tested feedback.</li>
<li>you can have a label in your documentation that it needs testing</li>
<li>have regular catch ups with your testers to get them to include new components in their tests</li>
<li>work closely with the teams implementing the components to see the good and the bad points of them trying to use the Design System.</li>
</ul>
</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Heydon Pickering</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-heydon-pickering.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-heydon-pickering.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="flexbox-holy-albatross" tabindex="-1">Flexbox Holy Albatross</h2>
<p>In their post-lunch talk at Patterns Day 2019, <a href="https://www.heydonworks.com">Heydon</a> talked about the flexbox holy albatross layout pattern.</p>
<p><a href="http://www.heydonworks.com/article/the-flexbox-holy-albatross">The Flexbox Holy Albatross</a></p>
<p>The Flexbox Holy Albatros, breaking it down:</p>
<ul>
<li>
<p>Flexbox, the CSS layout. A way of arranging boxes inside of other boxes.</p>
<ul>
<li>We also have grid, but flexbox is not superseded by grid</li>
</ul>
</li>
<li>
<p>Holy, as in Holy Grail, wanted to find a solution to a specific layout problem in web development</p>
</li>
<li>
<p>Albatross, an allusion to a famous rap by Sammy C. It’s in the name, because it took a long time to solve the problem.</p>
</li>
<li>
<p>The problem, a basic layout with a parent that has child elements, where flexbox fills the space with the child.</p>
</li>
<li>
<p>When you create a basic flexbox layout, you have <code>flexbox: wrap;</code> by default where a widow child element would fill the rest of the available space.</p>
</li>
<li>
<p>The problem is, that <code>flexbox: wrap;</code> the child item, to a user, is treated differently, because it looks different.</p>
</li>
<li>
<p>What if we could bypass the stage, where a widowed child element takes the full-width, but without breakpoints.</p>
</li>
</ul>
<blockquote>
<p>“Why not use breakpoints?”</p>
<p>“No.”</p>
</blockquote>
<ul>
<li>Pertinently, media queries are a hack. They don’t work with design systems, they don’t need to be in design systems.</li>
<li>The media is constant, but with media queries but the context is not.</li>
<li>What about using container queries? Nope.</li>
<li>We could use JengaScript, named because of it’s way of handling errors. If you write an error, or somebody else does - it won’t work.</li>
<li>There could be use of resize observer, note - this only handles pixels. not ems, rems, ch, etc.</li>
</ul>
<p><a href="http://www.heydonworks.com/article/the-flexbox-holy-albatross-reincarnated">The Flexbox Holy Albatross Reincarnated</a></p>
<ul>
<li>The layout has to make the decision, kinda like a boolean, which CSS doesn’t have. This can be done with CSS custom properties and the cascade which can “turn things off and on”.</li>
<li>max-width always beats width, similar with min-width and width.
<ul>
<li><a href="https://codepen.io/hteumeuleu/pen/VaZgqg">The Fab Four Technique</a></li>
</ul>
</li>
<li>If you have a negative flex-basis - it will default to zero.</li>
<li>if we wanted gutters we could use <code>gap</code> but this is (currently) only supported in FireFox.</li>
<li>You could create gutters with margins, but this could break unless you add more declarative rules.</li>
<li>So, add margins to everything, and then you can remove from it, as you’re surprising the negative values.</li>
<li>Bonus: we can use <a href="https://alistapart.com/article/quantity-queries-for-css/">quantity queries</a>. This allows the browser to work out what it needs to do with styling child elements, but without using media queries.</li>
</ul>
<blockquote>
<p>“You want to be your browsers mentor, not it’s micro manager”</p>
</blockquote>
<p><a href="https://every-layout.dev">Every Layout</a></p>
<ul>
<li>simple layouts, that can be built upon each other to create a component.</li>
<li>the layouts are using Web Components, so you can drop them into things like Vue, Preact, etc.</li>
<li>they feature ‘getters’ and ‘setters’, sensible defaults with composition over inheritance.</li>
<li>Web Components doesn’t show its CSS to the DOM - there is a fork of JSDOM that can do this using a transform in 11ty, and you need to remove ShadowDOM &gt; creates a unique string of all the styles and that can be added to the HTML.</li>
<li>From CSS into JavaScript into E-HTML into CSS into HTML.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Emil Björklund</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-emil-bjrklund.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-emil-bjrklund.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="meandering-towards-design-systems" tabindex="-1">Meandering towards Design Systems</h2>
<p>In the last talk of the day, <a href="https://twitter.com/thatemil">Emil</a> discusses how the industry moved towards Design Systems</p>
<ul>
<li><a href="https://blog.natbat.net/post/46614243624/css-systems">CSS Systems for writing maintainable CSS by Natalie Downe</a></li>
<li>We have things we build - style guides, pattern libraries - and previously Design System seemed something that we built.</li>
<li>To most they can still mean style guides and pattern libraries.</li>
<li>We can all, in this room, agree that they more complex than “How to build a design system in React?”</li>
<li>Donella Meadows - systems thinking — “A set of related components that work together in a particular environment to perform whatever functions are required to achieve the systems’ objective.”</li>
<li>“Dividing a cow in half does not give you two smaller cows” - Draper L. Kauffman Jr. “Systems one: An introduction to Systems Thinking”.</li>
<li>When we start to think of the system as a process, not a group of components we could say that every company has a Design System.</li>
<li>A Design System is never done but always moving to becoming.</li>
<li>Every organisation has a design system - either it’s delivered or accidental.</li>
<li>“Meta-design is much more difficult than design; it’s easier to draw something than to explain how to draw it” - Donald Knuth.</li>
<li>A Design Language is not about how it communicates with end-users, but the people that use the Design System.</li>
<li>Boundary Objects - people collaborate around objects.</li>
<li>Boundary Objects - need to exist outside your head</li>
</ul>
<p>Types of Boundary Objects:</p>
<ul>
<li>coincidental boundary - maps, shaded work surfaces</li>
<li>repository - code repos, databases</li>
<li>form - data formats, specimen collection sheets</li>
<li>ideal type - design pattern</li>
</ul>
<blockquote>
<p>“Can we make sure a product still feels cohesive and sole, even when many people work on it? Yes, if we have a shared understanding” - Alla Kholmatova</p>
</blockquote>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Danielle Huntrods</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-danielle-huntrods.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-danielle-huntrods.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="why-design-systems%3F" tabindex="-1">Why Design Systems?</h2>
<p>In their presentation at Patterns Day 2019, <a href="https://twitter.com/dhuntrods">Danielle</a>) talked about the topology of making a successful Design System.</p>
<ul>
<li>most of us are here today as we know, or believe that they help us do better work.</li>
<li>we care about doing better work as they help the outside world in the products that use them.</li>
<li>there is a lot of diversity in what is ‘best practice’ within the Design Systems community.</li>
<li>how do we know what would work for us.</li>
<li>topology.</li>
<li>systems that have worked well could be considered to have a better topology compared to those that have not.</li>
<li>We’re trying to solve problems that no individual can solve alone.</li>
<li>Repeated processes need to be broken down and can aid efficiency.</li>
<li>We have started looking at better ways to deliver projects with things like agile methodology but fundamentally we break things down.</li>
<li>There is much discussion about the naming of things, but not of the interconnectivity of those things which can lead to certain gaps.</li>
<li>unidentified gaps can cause confusion.</li>
<li>overlaps can appear - with duplication of efforts.</li>
<li>bad topology has certain symptoms:
<ul>
<li>duplication of efforts</li>
<li>conflict of ownership</li>
<li>incorrect implementations</li>
<li>recurrent miscommunication</li>
</ul>
</li>
<li>When breaking things down we can lose the overall context.</li>
<li>Breaking things down into components can lose context</li>
<li>Since we cannot anticipate every permutation we need to work on how things go together.</li>
<li>Consistent spacing helps put things back together again.</li>
<li>There can be gaps in skillset, if there are - there will be a struggle in achieving the goals.</li>
<li>There are overlaps in what people want the products to have, marketing want all the scripts, developers do not.</li>
<li>Solutions:
<ul>
<li>keep track of categories.</li>
<li>remember the end goal.</li>
<li>see the negative space.</li>
<li>choose your tools wisely.</li>
<li>establish a single source of truth.</li>
<li>set priorities for when conflict arise.</li>
</ul>
</li>
<li>It’s tempting to fallback on tools, but often it is a people problem. Communication is what can solve most problems.</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Amy Hupe</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-amy-hupe.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-amy-hupe.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="%E2%80%9Ccontent-is-king%E2%80%9D" tabindex="-1">“Content is King”</h2>
<p>In <a href="http://www.twitter.com/amy_hupe">amy's</a> talk at Patterns Day they discussed the crucial role of content in Design Systems.</p>
<ul>
<li><a href="http://gov.uk/design-system">gov.uk/design-system</a></li>
<li>13 team members working full-time.</li>
<li>Launched June 2018.</li>
</ul>
<h3 id="what-is-content-design%3F" tabindex="-1">What is content design?</h3>
<ul>
<li>content design is more strategic than copywriting</li>
<li>good content design helps people get to what they need as smoothly as possible</li>
<li>It’s based on user needs</li>
<li>“content that’s relevant for the right user at the nighttime in the right channels”</li>
</ul>
<h3 id="content-and-design-systems" tabindex="-1">Content and Design Systems</h3>
<ul>
<li>content in design systems can include
<ul>
<li>the content elements of components, like buttons text or form labels</li>
<li>the documentation of components, the structure of pages</li>
<li>the landing pages</li>
<li>technical documentation, like installation instructions</li>
<li>content best practices, like tone of voice</li>
<li>content about the system - like presentations, blogs, template answers for team members</li>
</ul>
</li>
</ul>
<p>A design system’s content helps people:</p>
<ul>
<li>find it</li>
<li>use it</li>
<li>contribute to it</li>
</ul>
<h3 id="documenting-components-and-patterns" tabindex="-1">Documenting Components and Patterns</h3>
<ul>
<li>Sorting</li>
<li>Naming</li>
<li>Explaining</li>
<li>Justifying</li>
</ul>
<p>As Design System owner and maintainer we are guiding people to use the system in a certain way. Without providing the information to how to use something, it will fail.</p>
<ul>
<li>context is key.</li>
<li>every organisation is different.</li>
<li>you content should be designed to match your organisations goals.</li>
<li>we can’t force people to use a system, so we need to help them choose it. Which starts with good documentation.</li>
<li>we can’t predict the user’s roles or experiences, so you need to be inclusive and include what is relevant.</li>
</ul>
<p>Good documentation can be aided by making it:</p>
<ul>
<li>Clear
<ul>
<li>Naming things help.</li>
<li>Start with a card sort and pattern cut-out session.</li>
<li>But - nobody can agree on anything.</li>
<li>As an industry we cannot all agree on what to name things.</li>
<li>Some people use Brad Frost’s Atomic Design.</li>
<li>Some call things components.</li>
<li>Some call them patterns.</li>
<li>Some call them both.</li>
<li>There is no right way.</li>
<li>User Research can help make the decision on naming.</li>
<li>at GDS components are like objects, so they use nouns.</li>
<li>at GDS patterns are ways of ding things, so they use verbs.</li>
<li>aliasing in the design system search can help people find what they are looking for.</li>
<li>in naming things you will never get consensus, just be consistent.</li>
<li>Consistent</li>
<li>consistency is really important for users to trust a design system</li>
<li>an internal style guide can help people use the correct terms when discussing the design system</li>
<li><a href="http://gov.uk">gov.uk</a> choose to discuss the design system in the third person which helps avoid the us/them potential thinking</li>
<li>Each component has a consistent page structure which helps be predictable, findable and trustworthy.</li>
<li>Using a fixed format helps contributors as well as users of the design system</li>
</ul>
</li>
<li>Useful
<ul>
<li>Good documentation is about writing the right things at the right time for the right reason.</li>
<li>Every line of content in your documentation is one more thing the users will have to do.</li>
<li>Use live examples rather than images - so it’s ‘real’ for people using the design system</li>
<li>Use real content when you can.</li>
<li>Provide examples with code so people can quickly copy and paste into their products to see how it looks</li>
<li>documentation for .<a href="http://gov.uk">gov.uk</a> does 5 jobs at once
<ul>
<li>how it looks</li>
<li>how it behaves</li>
<li>what copy to use</li>
<li>how it’s acessible</li>
<li>code to copy</li>
</ul>
</li>
<li>Honest
<ul>
<li>it’s easy to assume that a design system should provide all the answers.</li>
<li>if there is a gap in the documentation, be open and honest about those gaps.</li>
<li>it is the first steps to filling them.</li>
<li>sharing mistakes and failure should help others avoid them.</li>
<li>Include a ‘known issues and gaps’ for a pattern or component in the documentation.</li>
<li>This could help others contribute fixes, and additional information required to make the components and patterns improve over time.</li>
<li>being honest is not only helpful for the design systems users, but the people actually using the <a href="http://gov.uk">gov.uk</a> sites.</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Design Systems impact products and services. Products and service impact people.</p>
<p>Documentation matters - do it right.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Patterns Day 2019 - Alla Kholmatova</title>
      <link href="https://www.alwaystwisted.com/articles/patterns-day-2019-alla-kholmatova.html"/>
      <updated>2019-06-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/patterns-day-2019-alla-kholmatova.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="making-impact-with-design-systems" tabindex="-1">Making Impact With Design Systems</h2>
<p>In their presentation at Patterns Day 2019, <a href="https://www,twitter.com/craftui">Alla</a> discussed getting buy-in for your Design System from teams and leadership.</p>
<h2 id="why-should-our-teams-and-leadership-believe-in-design-systems%3F" tabindex="-1">Why should our teams and leadership believe in Design Systems?</h2>
<ul>
<li>
<p>Revenue</p>
</li>
<li>
<p>Brand and UX improvements</p>
</li>
<li>
<p>Efficiency</p>
<h3 id="revenue" tabindex="-1">Revenue</h3>
<p>Can consistency enabled by a design system, help improve conversions?</p>
<ul>
<li>
<p>2018, Alla managed to test if the consistency of Bulb’s site improved revenue.</p>
</li>
<li>
<p>They had to make sure conversion wasn’t hampered by changes.</p>
</li>
<li>
<p>They didn’t want to skew the results of the joining path by redesigning the sign up path.</p>
</li>
<li>
<p>They used the design system to update colours, and typography.</p>
</li>
<li>
<p>The results was 0.17% in favour of the using the design system.</p>
</li>
<li>
<p>“negligible really”.</p>
<p>Are there other ways to improve revenue?</p>
<ul>
<li>Design Systems can support experimentation and growth.</li>
<li>Mailchimp had a dramatic style change in 2018, base upon the original style guide.</li>
<li>“We parter with Growth to facility experimentation and testing of new patterns” - Alex Lehner, Mailchimp.</li>
<li>At Pinterest, a new element must out perform and existing element to be included.</li>
<li>Pattern experiments are unique to your system.</li>
<li>At <a href="http://Gov.uk">Gov.uk</a> they experimented with the progress indicator, without the indicator they time it took to complete a task didn’t change, so they removed the indicator.</li>
<li>At Habito, they found the form worked better, with a quicker progression with a progress indicator.</li>
<li>A pattern can work differently for different teams and products.</li>
</ul>
<h2 id="ux-and-brand" tabindex="-1">UX and Brand</h2>
<ul>
<li>
<p>Often we talk about how Design Systems make things cohesive.</p>
</li>
<li>
<p>The term cohesive is something Alla hears a lot.</p>
</li>
<li>
<p>“User experience often suffers not because of poor consistency but confusing information architecture and content design.”</p>
</li>
<li>
<p>“Design Systems can help implement and reinforce a visual brand.”</p>
</li>
<li>
<p>GDS is a good example of this. Before the .<a href="http://gov.uk">gov.uk</a> design system, there were 600-700 different UK government websites.</p>
</li>
<li>
<p>“People didn’t really know if they were on an official government website” - Tim Paul.</p>
</li>
<li>
<p>Whatever the reason, there needs to be organisational buy-in.</p>
</li>
<li>
<p>There needs to clarity on what the brand is.</p>
<p>To work out what your brand is, you need clarity. To do this, you can:</p>
<ul>
<li>
<p>purpose and values of the brand Design principles</p>
</li>
<li>
<p>Main screen design using new brand. Brand in context</p>
</li>
<li>
<p>Which then leads to new design patterns and documentation.</p>
<h2 id="efficiency" tabindex="-1">Efficiency</h2>
<ul>
<li>
<p>The top ‘key point’ of selling a Design System.</p>
</li>
<li>
<p>Marvel have a well established Design System</p>
</li>
<li>
<p>“We haven’t used our design system in the last year. We just needed to ship things really fast.” - Yavor Punchev, Marvel App</p>
</li>
<li>
<p>If a point of design systems is efficiency, why did this happen?</p>
</li>
<li>
<p>Work out what you need to invest time in to make things efficient.</p>
</li>
<li>
<p>Investing in form patterns, it allowed Bulb to save 50% of front-end time working on pages that needed forms.</p>
</li>
<li>
<p>FutureLearn, on the other hand, only has one or two forms, so investing the same time on form patterns would not be an efficient use of time.</p>
</li>
<li>
<p>A Design System needs to adopt through it’s product life cycle.</p>
</li>
<li>
<p>Not only looking at the growth and maturity uses.</p>
</li>
<li>
<p>Technology plays a very big part in keeping your Design System efficient</p>
</li>
<li>
<p>“Without React working on the design system alway felt like an uphill struggle.” - Jay Begum, FutureLearn.</p>
<p>Being strategic in what parts you invest in and when can make a really impact on your Design System.</p>
<p>“There needs to be a bigger goal, beyond the design system, for the system to have an impact.” - Alla</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Design Systems and CSS Grid on 24Ways</title>
      <link href="https://www.alwaystwisted.com/articles/design-systems-and-css-grid-on-24ways.html"/>
      <updated>2017-12-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/design-systems-and-css-grid-on-24ways.html</id>
      <content type="html">
        <![CDATA[
        <p>This year I have managed to tick one more thing off of my career 'bucket list', I wrote an article for <a href="https://24ways.org/">The Advent Calender for geeks, 24 Ways</a>.</p>
<p>I have been working on a clients design system for the last couple of years and recently we have started on looking at the future of the products it serves. One of the avenues we ventured down has shown us a requirement for some additional patterns for some marketing pages.</p>
<p>This allowed me to finally get to grips (a little) with CSS Grid in the look to phase out our current usage of Susy and replace it with CSS from the grid spec.</p>
<p>The article that I wrote for 24 ways shows my first adventure in putting CSS Grid into the existing design system. I think there's still parts of that article that can be expanded upon, and hope to do so in 2018.</p>
<p><a href="https://24ways.org/2017/design-systems-and-css-grid/">Design Systems and CSS Grid on 24Ways</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The Design Systems Newsletter</title>
      <link href="https://www.alwaystwisted.com/articles/the-design-systems-newsletter.html"/>
      <updated>2016-08-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-design-systems-newsletter.html</id>
      <content type="html">
        <![CDATA[
        <p>Let's be honest. <a href="styleguides-pattern-libraries-and-design-languages.html">Styleguides, Pattern Libraries and Design Systems</a> are pretty hot.</p>
<p>For the last 3 years I've been fortunate enough to work on various projects including extending existing pattern libraries, adding to a design system, and creating new pattern libraries and styleguides from (almost) the ground up.</p>
<p>I'm excited by the things I get to create for my clients everyday. I'm excited, seeing what other developers and designers who are also working on design systems, pattern libraries, and styleguides produce, publish and discuss. Every. Day.</p>
<p>Having 'cut my teeth' in curating <a href="http://www.sassnews.com">Sass News</a> before passing on the baton to <a href="http://www.twitter.com/jina">Jina</a>. After a small haitus, I was itching to start sharing what I'm reading again. I setup up a curated account, installed bookmarklets, a (much neccesarty) <a href="http://www.twitter.com/Design__Systems">twitter account</a> and was good to go.</p>
<p>Three issues in and getting close to 650 subscribers, I wanted to write a quick post.</p>
<p>Unlike Sass News where I decied to make it a weekly newsletter, this will be different. There's no real publishing schedule. It's not going to hit your inboxes at 9am(GMT) on Tuesdays...</p>
<p>The Design Systems Newsletter will be sent once I've collated around 7/8 links to artciles, code, frameworks that I feel's worth sharing. This way I won't feel 'pressured' into looking for things and I'll (hopefully) only fill your inboxes with quality content.</p>
<p>If you've not signed up, you can <a href="https://designsystems.curated.co/issues">read the previous emails</a>, and then <a href="https://designsystems.curated.co">subscribe to the newsletter</a>.</p>
<p>As I've mentioned I'm really excited when I see people working on similar problems, codebases, and products and sharing their findings, thougths, and code. If you ever come across something that you think should be featured, don't hesitate to <a href="http://www.twitter.com/StuRobson">let me know</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Better Ghost Button Hover Effect</title>
      <link href="https://www.alwaystwisted.com/articles/a-better-ghost-button-hover-effect.html"/>
      <updated>2016-03-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-better-ghost-button-hover-effect.html</id>
      <content type="html">
        <![CDATA[
        <p>I was visiting Clearleft’s <a href="http://www.clearleft.com">website</a> the other day and noticed a <a href="https://uxmag.com/articles/15-ethereal-examples-of-ghost-buttons-in-action">‘ghost button’</a> on the home page that was a little bit, well, off.</p>
<p>Moving my cursor across the screen the button ‘jumped’ when hovering. Only slightly (really) but enough for me to take a dive into Firefox’s developer tools.</p>
<h2 id="using-border" tabindex="-1">Using border</h2>
<p><img src="http://alwaystwisted.com/images/before.gif" alt="image of before" loading="lazy" decoding="async"></p>
<p>In the animated gif above we can see how, when the cursor moves over the button gets a little wider and taller and in doing so makes it look a little ‘off’.</p>
<p>The code used for this effect on the button is something akin to this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.button-cta</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.button-cta:hover</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 2px solid #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>This makes the button appear to be 2px wider and 2px taller on hover and means that it ‘moves’ on the page when hovered as it pushed the button down by a pixel and across by a pixel.</p>
<p>I wondered if there was a more pragmatic, progressive fix for this.</p>
<h3 id="making-it-better-box-shadow" tabindex="-1">Making it better box-shadow</h3>
<p>Instead of using an actual border property for the effect I tried using box-shadow. It seems to work pretty well in this case and doesn’t make the button ‘jump’ at all when hovered.</p>
<p><img src="http://alwaystwisted.com/images/after.gif" alt="after" loading="lazy" decoding="async"></p>
<p>In the animated gif above we can see that, now using box-shadow, we get a similar effect but without the button jumping when the cursor hovers over it.</p>
<p>The CSS I added to the button (removing the CSS for the border) was something like this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.btn-cta</span> <span class="token punctuation">{</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 1px #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.btn-cta:hover</span> <span class="token punctuation">{</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 2px #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="in-codepen" tabindex="-1">In CodePen</h3>
<p>Animated images are all well and good and the code examples above don’t really show you <em>too</em> much. So I’ve created <a href="http://codepen.io/sturobson/pen/311483e372532833ce840bc470eb3f0d?editors=1100">a quick CodePen</a> with working examples of a button using border and one using box-shadow.</p>
<p>See the Pen <a href="https://codepen.io/sturobson/pen/311483e372532833ce840bc470eb3f0d/">a better ghose button</a> by Stuart Robson (<a href="https://codepen.io/sturobson">@sturobson</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<h3 id="on-support" tabindex="-1">On Support</h3>
<p>It’s 2016, browser support for box-shadow is pretty good (if you go with global statistics). According to <a href="http://www.caniuse.com">caniuse.com</a> it’s available on <a href="http://caniuse.com/#feat=css-boxshadow">91.33% of browsers being used daily</a>. That other ~8 percent though. IE8 and Opera mini (5–8), let’s not forget those. We need to look at doing something <a href="http://dowebsitesneedtolookexactlythesameineverybrowser.com/">similar</a>.</p>
<h4 id="ie8-fallback" tabindex="-1">IE8 Fallback</h4>
<p>For IE8 we can use a <a href="https://css-tricks.com/how-to-create-an-ie-only-stylesheet/">conditional comment</a> to target that browser by having a HTML class available. We could perhaps keep the border or we could remove the border and add text-decoration on hover, something like:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.lt-ie8 .btn-cta</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #fff<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.lt-ie8 .btn-cta</span> <span class="token punctuation">{</span>
  <span class="token property">text-decoration</span><span class="token punctuation">:</span> underline<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="opera-mini" tabindex="-1">Opera mini</h4>
<p>Instead of creating a fallback, let’s look at making something progressively enhanced. Let’s first off add some JavaScript that will test if the browser supports box-shadow:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'detect'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>boxShadow <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  document<span class="token punctuation">.</span><span class="token function">getElementsByTagName</span><span class="token punctuation">(</span><span class="token string">'html'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>className <span class="token operator">+=</span> <span class="token string">' boxshadow'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Now we can write some CSS that will work giving Old IE, Opera Mini and the original border effect and if the browser does have box-shadow and JavaScript doesn’t fail to load we get the nicer effect using box-shadow:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.btn-cta</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 1px solid currentColor<span class="token punctuation">;</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 1px currentColor<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.btn-cta:hover</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 2px solid currentColor<span class="token punctuation">;</span>
  <span class="token property">box-shadow</span><span class="token punctuation">:</span> 0 0 0 2px currentColor<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.boxshadow .btn-cta</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.boxshadow .btn-cta:hover</span> <span class="token punctuation">{</span>
  <span class="token property">border</span><span class="token punctuation">:</span> 0<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="over-engineering" tabindex="-1">Over Engineering</h3>
<p>Is this solution too much? I guess when you look at supporting as many browsers as you possibly can, then maybe it looks that way. Perhaps you could forgo the support for Opera Mini (5–8) as the button will still have the whitespace around it to make it look not like a paragraph of text. You could change how you create the 'button'. Perhaps only add a style reset for anything with box-shadow and leave OldIE and older Opera mini browsers with a default button style. Whatever's fit for yours and your users needs. Personally I’d be happy to add a couple more lines of CSS for this so that it can work for as many browsers as possible.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Determining CSS Units For Your Pattern Library</title>
      <link href="https://www.alwaystwisted.com/articles/determining-css-units-for-your-pattern-library.html"/>
      <updated>2016-03-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/determining-css-units-for-your-pattern-library.html</id>
      <content type="html">
        <![CDATA[
        <p>For some time now I’ve been working on an inherited codebase, moving it from it’s original single purpose of being a website to a cohesive design language with a pattern library and front-end framework.</p>
<p>One part of doing this is looking at the existing code to see if it’s possible to improve it and, as one of our underlying goals, make it easier to understand and more ‘human-readable’.</p>
<p>In doing that we’ve uncovered a few things that could be improved and more consistent. One of those things is how CSS units are being used.</p>
<h2 id="types-of-units" tabindex="-1">Types Of Units</h2>
<p>There are <a href="https://css-tricks.com/the-lengths-of-css/">quite a few lengths of CSS</a> available and looking at the existing CSS (that currently uses Sass) we have found these 5 being used:</p>
<ul>
<li>em</li>
<li>rem</li>
<li>px</li>
<li>%</li>
<li>vh</li>
</ul>
<p>The majority of the time a <code>rem</code> is in use with a <code>px</code> fallback for Old IE. This is using a Sass mixin to create the <code>rem</code> value from the <code>px</code> value variable used in the mixin.</p>
<p>All of the units are found in use for fonts, margins, paddings, borders, widths, heights, line-heights and media queries. Along with things like box-shadow and text-shadow.</p>
<p>As we are trying to make the CSS used within the pattern library easier to read and understand I’m now looking at ‘guidelines’ as to what CSS unit should be used where.</p>
<h2 id="categorising-css-unit-usage" tabindex="-1">Categorising CSS Unit Usage</h2>
<p>So far I’ve got this:</p>
<h3 id="ems" tabindex="-1">ems</h3>
<p>The <code>em</code> unit is only to be used within media queries. Currently most media queries are created using a Sass mixin and variable or value to define the min-width.</p>
<h3 id="px" tabindex="-1">px</h3>
<p>I think we must restrict the use of <code>px</code> to box-shadow, text-shadow, border and height. Anything that could look a little bit silly when you zoom on a desktop browsers.</p>
<h3 id="rem" tabindex="-1">rem</h3>
<p>Any font-size or vertical spacing should use the <code>rem</code> unit. To have consistent rhythm if the browser is resized or in between media queries.</p>
<h3 id="%25" tabindex="-1">%</h3>
<p>Percentages should be used only for all things horizontal. Widths, left and right margins or padding.</p>
<h3 id="unitless" tabindex="-1">unitless</h3>
<p>We should not use any CSS unit when <a href="http://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/">defining our line-height</a>.</p>
<h3 id="vh" tabindex="-1">vh</h3>
<p>A ‘special’. The <code>vh</code> unit is currently only used on one aspect of the homepage.</p>
<h2 id="moving-forward" tabindex="-1">Moving forward</h2>
<p>In defining new guidelines and implementing them on a codebase it can create better consistency within the pattern library and overall design language. This will help the maintainability, the usage and the development of the codebase.</p>
<p>Although deciding upon, defining and sticking to guidelines for such a marginal part of the codebase could seem a little over-engineered there are several improvements of this ‘size’ in the works which should lead to a better, more consistent design system which I hope will empower other teams to start using it on their projects.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Web Developers New Working Week</title>
      <link href="https://www.alwaystwisted.com/articles/a-web-developers-new-working-week.html"/>
      <updated>2016-03-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-web-developers-new-working-week.html</id>
      <content type="html">
        <![CDATA[
        <p>Why spend the week in your comfort zone, working on the same browser under the same conditions you’re used to. Let’s switch it up a bit.</p>
<h3 id="tap-tap-monday%3A" tabindex="-1">Tap Tap Monday:</h3>
<p>Monday’s is the day to unplug your mouse and test your work using only the keyboard for navigating the site you’re working on.</p>
<h3 id="grayscale-tuesday" tabindex="-1">Grayscale Tuesday</h3>
<p>Tuesday is the day to test your work for various forms of colour blindness.</p>
<p><a href="https://chrome.google.com/webstore/detail/spectrum/ofclemegkcmilinpcimpjkfhjfgmhieb?hl=en">Spectrum - a Chrome extension</a></p>
<p><a href="https://addons.mozilla.org/en-GB/firefox/addon/colorblind-design/">Colorblind Design - a Firefox extension</a></p>
<h3 id="different-browser-wednesday" tabindex="-1">Different Browser Wednesday</h3>
<p>Wednesday’s… If you’re used to developing for most of your day in <a href="https://www.mozilla.org/en-GB/firefox/new/">Firefox</a>, try <a href="https://www.google.com/chrome/">Chrome</a>, if you’re using <a href="https://www.microsoft.com/en-gb/windows/microsoft-edge">Edge</a> try <a href="http://www.opera.com/">Opera</a>. Today’s the day to break out into a different browser for the day to develop in.</p>
<h3 id="throttle-thursday" tabindex="-1">Throttle Thursday</h3>
<p>Thursday is the <a href="http://fourkitchens.com/blog/article/throttled-thursdays">day to throttle your connection</a>. There’s a whole host of ways to do this (most of which are <a href="http://fourkitchens.com/blog/article/throttled-thursdays">shown in this blogpost</a>) my personal favourite is <a href="http://slowyapp.com/">Slowy</a>.</p>
<h3 id="friday" tabindex="-1">Friday</h3>
<p>It’s Friday. The working week is nearly over. Enjoy the day in the comfort of your own browser and don’t forget the #deskbeer at 4pm.</p>
<p>Although this post is 'a bit of fun'. There's some sense in testing for various scenarios. I've not even mentioned 'turn JavaScript off for the weekend', you can decide to do that yourself.</p>
<p>I don’t care if Monday’s blue, Tuesday’s grey and Wednesday too. Thursday I don’t care about you. It’s Friday I’m in love.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Using Lists In A Yeoman Generator</title>
      <link href="https://www.alwaystwisted.com/articles/using-lists-in-a-yeoman-generator.html"/>
      <updated>2016-01-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/using-lists-in-a-yeoman-generator.html</id>
      <content type="html">
        <![CDATA[
        <p>For a large project I’ve been working on with Monotype I recently, through some requirement changes, needed to create a list of options in <a href="http://yeoman.io/">Yeoman Generator</a>. After some quick googling I found that the best option for me was to use the list type available.</p>
<p>Further reading various Stack Overflow questions and answers, examples from the <a href="https://github.com/SBoudrias/Inquirer.js">inquirer.js repo</a> and any documentation I was a little flummoxed.</p>
<p>Every example I could find gave simple one-word options. This works when choosing what size of pizza you require:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> prompts <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'list'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'features'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What do you want to make today?'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'Jumbo'</span><span class="token punctuation">,</span> <span class="token string">'Large'</span><span class="token punctuation">,</span> <span class="token string">'Standard'</span><span class="token punctuation">,</span> <span class="token string">'Medium'</span><span class="token punctuation">,</span> <span class="token string">'Small'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span>
  prompts<span class="token punctuation">,</span>
  <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// do things with the answer here</span>
  <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>For this project I needed a more descriptive explanation of what they were about to install. Was it a project for a new typeface specimen? A new email project? A quick prototype? We needed to be able to be verbose with out list of choices.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> prompts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
<span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'list'</span><span class="token punctuation">,</span>
<span class="token literal-property property">name</span><span class="token operator">:</span> ‘project’<span class="token punctuation">,</span>
<span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What type of project do you want to create today?'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        “a <span class="token keyword">new</span> <span class="token class-name">email</span> campaign“<span class="token punctuation">,</span>
        “a low fidelity prototype“<span class="token punctuation">,</span>
        “a <span class="token keyword">new</span> <span class="token class-name">typeface</span> specimen“<span class="token punctuation">,</span>
        “a <span class="token keyword">new</span> <span class="token class-name">landing</span> page“<span class="token punctuation">,</span>
        “a <span class="token keyword">new</span> <span class="token class-name">bespoke</span> article”
    <span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">prompt</span><span class="token punctuation">(</span>prompts<span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// do things with the answer here</span>
<span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Looking at this and how the simpler example had one-word answers I thought this would be a problem when it came to assigning the choice made to various options that may or may be required.</p>
<p>I searched the documentation, various blogposts and Stack Overflow (again) for an answer and then I tried something.</p>
<p>Taking a look at the <a href="https://github.com/yeoman/generator-gulp-webapp">gulp web app generator</a> from the Yeoman Github organisation I looked at how they had used the checkbox type from inquirer.js –</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> prompts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
  <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'checkbox'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'features'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What more would you like?'</span><span class="token punctuation">,</span>
  <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Sass'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includeSass'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">checked</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Bootstrap'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includeBootstrap'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">checked</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Modernizr'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includeModernizr'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">checked</span><span class="token operator">:</span> <span class="token boolean">true</span>
  <span class="token punctuation">}</span><span class="token punctuation">]</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token comment">//</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Here we had name, value and checked. Well I knew I didn’t need checked so I tried using name and value. It worked.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> prompts <span class="token operator">=</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'list'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'features'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">message</span><span class="token operator">:</span> <span class="token string">'What do you want to make today?'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">choices</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'a new email campaign'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includeEmail'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'a low fidelity prototype'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includePrototype'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'a new typeface specimen'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'includeSpecimen'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token comment">//</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Now, using <code>name</code> we can have a verbose, descriptive option and use it’s <code>value</code> when generating a new project to include the relevant files, bits of HTML or CSS, images, fonts etc.</p>
<p>So now, when we are in a terminal window and <code>Yo</code> the generator we get a nice list to choose one option from.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Styleguides, Pattern Libraries and Design Languages</title>
      <link href="https://www.alwaystwisted.com/articles/styleguides-pattern-libraries-and-design-languages.html"/>
      <updated>2016-01-20T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/styleguides-pattern-libraries-and-design-languages.html</id>
      <content type="html">
        <![CDATA[
        <p>The terminology surrounding front-end ’styleguides’ seems to be ever expanding. We have styleguides, pattern libraries, UI libraries, design systems, design patterns and a design language to name a few.</p>
<p>Some of these are similar to each other, some are used to encompass everything. For clarity it’s best to define what you are meaning when using one of these terms. It will help you and your colleagues understand what part of the project you are talking about without possible confusion.</p>
<p>This is how I see three of the often used terms. Style guides, Pattern Libraries and Design Languages.</p>
<h2 id="the-what%2C-the-where%2C-the-how-and-the-why." tabindex="-1">The what, the where, the how and the why.</h2>
<h3 id="pattern-libraries" tabindex="-1">Pattern Libraries</h3>
<p>A pattern library is a collection of front-end code that creates a component part of the overall design of the page. It is ‘the what’ of the website. If you need to use a carousel this is ‘what’ code you would use.</p>
<h3 id="styleguides" tabindex="-1">Styleguides</h3>
<p>With a pattern library being ‘the what’ of a sites design a styleguide is ‘the how’ and ‘the where’. You have this collection of colours and typefaces and the styleguide will show you how and where to put them in your website. The patterns you need for a project will have their placement and usage defined within the styleguide.</p>
<p>It is ‘a guide’ though. It should allow for deviation where necessary or chosen when content dictates a change in the design.</p>
<h3 id="design-language" tabindex="-1">Design Language</h3>
<p>As we have ‘the what’, ‘the where’ and ‘the how’ then a Design Language, in part, is the overall ‘the why’. With our ready–made patterns and our styleguide showing us where and how to use them the Design Language will instruct us as to why we would use ‘the what’ and’(the) where’ we should put them altogether.</p>
<h2 id="the-simplest-of-terms" tabindex="-1">The simplest of terms</h2>
<p>That’s how I see these three terms, like a ‘Johnny Ball Reveals All’ trio for projects.</p>
<p>Out of the three I think I’ve not given the Design Language as much credit as to what it is. It can be seen as much more than the simple why you would put what where and how. It should be the living, growing ‘thing’ for the project, in all aspects of design, not just of the web. From my point of view, as a front-end developer, that’s for others to define and express better that I could try to.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Getting Buy In For Your Styleguide</title>
      <link href="https://www.alwaystwisted.com/articles/getting-buy-in-for-your-styleguide.html"/>
      <updated>2016-01-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/getting-buy-in-for-your-styleguide.html</id>
      <content type="html">
        <![CDATA[
        <blockquote>
<p>“If you book them, they will come.”</p>
<p>(not) Jim Morrison</p>
</blockquote>
<p>In creating a front-end styleguide, design language and framework for (initially) a small part of a company, getting ‘buy in’ from other departments and developers could be a potential problem.</p>
<p>Here’s this collection of files you’ve created that help you with your day–to–day work with a pattern library of your website, but how can that possibly help another department, or even another company within a larger organisation.</p>
<p>Part of it comes down to how you have gone about creating your design language, your pattern library and your front-end framework. Part of it is how you go about evangelising what you’ve created.</p>
<p>A style guide, built upon a pattern library that is part of the design language is just that. A guide (more on this, in another article (to be written)). It is not ‘the law’, it should have the ability to be wielded masterfully by another designer, to be modified, adapted, re-written (in parts) to suit the sites design and requirements.</p>
<p>In an organisation with many teams potentially creating sites that could be poles apart from each other a clear front-end architecture of possibilities with a component–based, modular pattern library can be of great benefit to all.</p>
<p>You should bestow the virtues of using your front-end framework and pattern library, showing how that, if every developer started using it, it would improve not only itself but the websites that are the customer / visitor / user facing.</p>
<p>The ‘thing’ (the front-end framework and pattern library) can be improved, by everyone, be it someone who’s part of the ‘original team’ or another developer working for another company or part of the organisation.</p>
<p>Using version control and creating a system of how to update the codebase, maybe with peer review, means everyone in the organisation can have their say, giving their opinion on edits to the code all the while helping the overall ‘thing’ and a sites visitor.</p>
<p>If everyone within a large organisation uses the same front-end framework and architecture it allows for an increasing improvement in code quality, bringing new and/or better design patterns, performance improvements all leading to ‘better’ sites (from a code perspective) for everyone.</p>
<p>This can be of benefit, not only to someone visiting the site with a more performant faster page and better accessibility, for example, but also to the organisation as a whole.</p>
<p>If every developer on every project starts to use the same front-framework, the same pattern library it can make it easier for developer to switch teams, or ‘jump in’ as an extra pair of hands. Using the same base elements of the front-end architecture means the developer will be ‘up to speed’ in no time. That’s got to be a good thing.</p>
<p>I think there are many benefits for a company to treat their front-end framework and pattern library as a going concern, there is always room from improvement, the work is never ‘done’.</p>
<blockquote>
<p>“No matter how good you get you can always get better, and that’s the exciting part.”</p>
<p>Tiger Woods</p>
</blockquote>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Deleting Git Tags Locally and on Github</title>
      <link href="https://www.alwaystwisted.com/articles/deleting-git-tags-locally-and-on-github.html"/>
      <updated>2015-06-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/deleting-git-tags-locally-and-on-github.html</id>
      <content type="html">
        <![CDATA[
        <p>So, I’m currently in the depths of helping a client with getting the front-end of their design language off the ground and also a neat little Yeoman generator to allow anyone working for them to quickly spin up some basic HTML and use the design language.</p>
<p>Git tags can be used to specify points in the history of a project as something important. Usually these are used to mark releases(v0.0.01, and so on). I’m using tags in these projects so that my client can easily update their copy of the Yeoman generator on their machine when a new feature or bugfix has been implemented.</p>
<p>The design language is making use of <a href="http://www.bower.io">Bower</a> so that it gets pulled in (or not) nice and simple into the Yeoman framework that’s being created.</p>
<p>Using both Bower and Yeoman has required me tagging some commits to the repo with a version number.</p>
<p>At some point, probably a Friday, I was getting annoyed with the version numbers I was using expotentially on something that wasn’t near completion. I decided to nuke all the git tags both locally and remotely so that I could (cheekily) start again.</p>
<h3 id="delete-all-git-tags-locally" tabindex="-1">Delete all Git tags locally</h3>
<p>To delete all the git tags locally I happened upon this line of code to enter into the command line. This wil irrecoverably remove any and all of the git tags within the folder you enter the code in terminal.</p>
<p>git tag -d <code>git tag | grep -E '.'</code></p>
<h3 id="delete-all-tags-in-a-remote-repo" tabindex="-1">Delete all tags in a remote repo</h3>
<p>Finally to delete all of the tags in the remote repo also I found this line of code that did the job. This wil irrecoverably remove any and all of the git tags from the attached remote server of the folder you enter the code in terminal.</p>
<p>git ls-remote --tags origin | awk '/^(.<em>)(s+)(.</em>[a-zA-Z0-9])$/ {print ':' $2}' | xargs git push origin</p>
<p>Some pretty horrendous and scary looking regex’d git codings but it worked perfectly.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Jump Start Sass</title>
      <link href="https://www.alwaystwisted.com/articles/jump-start-sass.html"/>
      <updated>2015-06-03T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/jump-start-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>UPDATE: I'm no longer writing this.</p>
<p>So, I'm co-writing a <a href="https://learnable.com/books/jump-start-sass">book</a>. On <a href="http://www.sass-lang.com">Sass</a>. With <a href="http://www.twitter.com/hugogiraduel">Hugo</a>. For <a href="http://www.sitepoint.com/">SitePoint</a>.</p>
<p>It will introduce preprocessors, the basic tenets of Sass, project architecture and the ecosystem surrounding the language.</p>
<p>I'm really excited, not only do I get to work with Hugo, we are also lucky to have the awesome <a href="http://www.twitter.com/kaelig">Kaelig</a> as our technical editor.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A New Workshop at WebDevConf</title>
      <link href="https://www.alwaystwisted.com/articles/a-new-workshop-at-webdevconf.html"/>
      <updated>2015-06-02T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-new-workshop-at-webdevconf.html</id>
      <content type="html">
        <![CDATA[
        <p>I'm really happy to announce, after the success of last years workshops, that I'll be presenting a new workshop on 'Getting Super Powers with Sass' at this years WebDevConf in Bristol.</p>
<h3 id="getting-super-powers-with-sass" tabindex="-1">Getting Super Powers with Sass</h3>
<p>So, you’re comfortable with CSS but you really want to jump into a telephone box and fly away with Sass as your new super power. Getting Super Powers with Sass will show you the basics of the programming language before flying into practical and pragmatic uses to make creating CSS as easy as putting on your cape.</p>
<p>The workshop will teach</p>
<ul>
<li>The Sass basics of nesting, variables, mixins, extends, placeholders and functions.</li>
<li>How to decide upon an ideal file and folder architecture.</li>
<li>Creating mixins for common snippets of CSS.</li>
<li>How to write and maintain variables for a project.</li>
<li>Where to ‘stop’ when using Sass in your code.</li>
<li>Where Sass fits within a modern front-end architecture, looking at Gulp and Grunt.</li>
</ul>
<p>The workshop will be have aspects where you will need to use a laptop, this ideally will also need Sass installed.</p>
<h3 id="about-the-event" tabindex="-1">About the event</h3>
<p>WDC (webdevconf) is a one day conference held in Bristol each year, with a day of workshops held beforehand. My workshop (Getting Super Powers with Sass) will run on Thursday 8th October 2015 in the afternoon.</p>
<p><a href="http://2015.webdevconf.com/workshops">More information available here.</a></p>
<h3 id="testimonials" tabindex="-1">Testimonials</h3>
<p>Here are a few testimonials from previous workshop attendees.</p>
<blockquote>
<p>“An amiable, engaging and extremely useful run through Sass from top to bottom. Stu concisely covered the basics, followed up with some nifty advanced techniques and wrapped up the day with a Q&amp;A on structuring Sass projects.”</p>
<p>Dan Dineen - <a href="http://www.bath.ac.uk/">University of Bath</a></p>
</blockquote>
<blockquote>
<p>“Stu did a fantastic job making Sass accessible to beginners. The workshop was incredibly practical, light on preaching and heavy on pragmatism. Even an old dog like me, came away wanting to give Sass another go. Highly recommended!”</p>
<p>Alex Morris - <a href="http://www.adobe.com/">Adobe</a></p>
</blockquote>
<blockquote>
<p>“The workshop was well balanced, Stuart shared examples and got us using Sass within minutes of the workshop starting, it was a practical hands-on introduction from a clear expert. The relaxed &amp; informal setting made it a pleasure to attend. ”</p>
<p>Steve Kirkley - <a href="http://www.twitter.com/stevekirtley">@stevekirtley</a></p>
</blockquote>
<blockquote>
<p>“Stu’s knowledge of Sass and his way of explaining the ins and outs, for me, are unparalleled to anyone else I know.  Highly recommended if you are new to Sass, or are interested in increasing your understanding of this wonderful language.”</p>
<p>Nick Toye - <a href="http://www.nicktoye.co.uk/">Pixels &amp; Code</a></p>
</blockquote>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Workflows and Tooling</title>
      <link href="https://www.alwaystwisted.com/articles/workflows-and-tooling.html"/>
      <updated>2015-05-20T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/workflows-and-tooling.html</id>
      <content type="html">
        <![CDATA[
        <p>Before I decided to venture out and become a full-time front-end developer my day job was quite different. I worked for a conference set and stage design company. I didn’t design the sets. I was in the warehouse making up the stock we had to fit the design in both size and colour variations.</p>
<p>The company had a large stock of ‘flats’ ready to be covered in a felt, pvc or kiss laminate of the clients choosing. It was a case of getting the flats required, cutting the fabric and bubble wrap for protection and then some stapling and tapin up ready for transport.</p>
<p>The company is about 18 years old now. When I left in 2012 there were a couple of flats that were as old as the company. From the first contract it got. If you look at those flats you can see the progression in tooling and workflow from those small beginnings to how the company works today.</p>
<p>So, let’s take a basic 8 foot by 4 foot flat. The face is a 5mm sheet of plywood which is glued and stapled on to a backing frame of 2 inch by 1 inch timbre. This makes the flat 8 foot by 4 foot by (about) 2 inches.</p>
<p>To cover a flat in fabric you would need to wrap your chosen fabric around so that the face and all sides are covered leaving the back sparse and bare (as the audience won’t be seeing that bit).</p>
<p>Going back to the these ‘antique’ flats that were kicking about. They were 8 foot by 4 foot. If you looked at the back you could see:</p>
<ul>
<li>that when the company first started the fabric was stapled onto inside of the 2x1 timber. You can still see the staples from a hand stapler that tacked the fabric on</li>
<li>a second look reveals the time when the company invested in air tools and the hand stapler was replaced with an air gun that easily sped up production.</li>
<li>a third look shows that the fabric is now stapled onto the edge of the 2x1 timber saving time because it’s easier and just as effective but also allows creation of larger panels because the fabric has a little more play to stretch.</li>
</ul>
<p>So, over the lifetime of the company, so far, they developed and adapted their workflow and tooling to help speed things up and create more possibilities. This in turn led to reduced company costs which were passed onto the clients and the profit margin.</p>
<p>Moving from a hand stapler which you have (pretty much) full control of to an air gun that’s pushing out staples with 100psi of pressure would be pretty daunting. You lose a bit of ‘the feel’ of control and if not used wisely you could end up stapling your thumb (which I did more than once).</p>
<p>When looking at modern workflows and tooling presented to us in web development it’s easy to quickly cast aspersions on things as we give a little bit of control away.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Updating Dependencies in a package.json</title>
      <link href="https://www.alwaystwisted.com/articles/updating-dependencies-in-a-packagejson.html"/>
      <updated>2015-05-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/updating-dependencies-in-a-packagejson.html</id>
      <content type="html">
        <![CDATA[
        <p>I am currently working for a client helping to build out a front-end framework, design pattern library for them to use throughout their company, for both internal teams and developers as well as external agencies and freelancers (like myself). A project that can will allow for simple prototyping, making a marketing site and beyond.</p>
<p>Together we have been reiterating the requirements of what is needed and have added and removed things as necessary. The whole package will be distributed using Yeoman. We picked the “web’s scaffolding tool” because of the various parts of the codebase that may or may not be required for any project it might get used on.</p>
<p>To start, I picked out the preexisting gulp webapp Yeoman generator to work on and adapt as needed. From the off this is fantastic as it allows a quick setup and creation of a project folder but the way the gulpfile.js is written does not and will not suit the needs of the entire project going forward.</p>
<p>As this was decided I made a start hacking together a gulpfile.js that would work for the project goals. This was by taking bits of the existing JavaScript, borrowing bits from another gulp-based boilerplate I have been using and adding new code and plugins as required.</p>
<p>Doing this leaves the package.json file in a bit of a mess. Borrowing from here and there I could not be sure if I was up-to-date on all the packages I included.</p>
<p>I wanted a way to update all of the dependencies in a quick and painless manner.</p>
<h2 id="updating-%E2%80%98all-the-things%E2%80%99" tabindex="-1">Updating ‘all the things’</h2>
<p>After typing various combinations of words into a search engine. I clicked on a result that took me to <a href="http://npmjs.com/package/npm-check-updates">npm-check-updates</a>. This Node module when invoked on the command line will run through your package.json file, check to see if each dependency is the latest and, depending on what else you give in the command, replace the dependency version number with the latest.</p>
<p>To install the Node module you enter the following code into your terminal and let it fly off and install itself globally.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> npm-check-updates <span class="token parameter variable">-g</span></code></pre>
<p>After this is installed you would need to <code>cd</code> into the relevant project folder. If you then type:</p>
<pre class="language-bash"><code class="language-bash">npm-check-updates</code></pre>
<p>You will be presented with what packages you have and then if there is an update for each one.</p>
<p>To update all of the dependencies within that package.json you would enter:</p>
<pre class="language-bash"><code class="language-bash">npm-check-updates <span class="token parameter variable">-u</span></code></pre>
<p>To only see if certain dependencies are out-dated (for example, gulp-sass) and have newer versions you would use something like:</p>
<pre class="language-bash"><code class="language-bash">npm-check-updates <span class="token parameter variable">-f</span> gulp-sass</code></pre>
<p>So, this is great. The Node module helps me quickly check to see if the dependencies are up-to-date and (if I choose to) update them (all) if required.</p>
<p>This is only half way there though. I have already got a folder of Node modules. So I need to override what is there already now that I have an updated package.json.</p>
<h2 id="back-to-day-0" tabindex="-1">Back to day 0</h2>
<p>I decided the easiest way to do this was to delete the folder completely and re-install the dependencies. As we are in terminal, we can do it all from the command line too. Making sure we are in the correct project folder we would simply write:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">rm</span> <span class="token parameter variable">-fr</span> node_modules</code></pre>
<p>Which would make sure (-f, force) we remove all of the files and folders (-r, recursively) in one go (-fr). After that has happened we will then need to re-install all of the depenencies again:</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span></code></pre>
<p>Now we have got a an up-to-date project, using the latest (chosen) gulp dependencies for our awesome website making. Automating this as much as possible to a few lines of code for the command line helps speed up and maintain a working project. There should, of course, be a slight note of caution. Running npm-check-updates -u whilst quickly updating all the dependencies within your package.json could by doing so break things where and updated dependency has changed.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The Conference Audience</title>
      <link href="https://www.alwaystwisted.com/articles/the-conference-audience.html"/>
      <updated>2015-03-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-conference-audience.html</id>
      <content type="html">
        <![CDATA[
        <blockquote>
<p>“If you’ve not got anything nice to say, then don’t say anything at all”</p>
</blockquote>
<p>A phrase I’m sure many people could say they’ve heard from a parental voice at a young age. I’m sure it was possibly something Basil Fawlty would’ve said during “The Kipper And The Corpse” too.</p>
<p>In 2014, I was overjoyed to have been able to speak at various meetups and some conferences too.</p>
<p>Unbeknownst to anyone that follows me on the twitters but hasn’t spent time with me in real life. I can am not really the ‘social butterfly’ I am when sending a beautifully crafted subtweet behind a 13' Retina MacBook screen.</p>
<p>I’m quite the introvert, I can spend most of the working day without any conversation. I don’t mind that. Part of the reason I wanted to talk was to try and ‘break out’ of being a shell of my online self. I used to play guitar in a band when I was growing up. I played ‘lead’ but I didn’t have the persona of a lead guitarist. Often at gigs I’d have my back to the audience. Only listening to my guitar and the snare drum through an monitoring system that was available. To be honest. I’m not a fan of being ‘in the limelight’ in reality. The barrier of a screen helps me be someone a little different.</p>
<p>So, to try and ‘break out’ I decided to put in talk proposals, ask to speak at a few meetups and I was fortunate to be asked to speak (at the first online Sass Summit) too.</p>
<p>I don’t think I want to doing any public speaking anymore. In part, I guess you could say unfortunately, this is due to some criticism from audience members at the last couple of talks I gave. I know words shouldn’t hurt but they easily do when you’re miles from home and family and extremely tired too.</p>
<p>I was ‘accused’ (a strong word, my choice) of falling asleep during a talk I was giving. That hurt, I was tired. Tired with nerves and lack of sleep. At a different event I dissapointed a member of the audience due to my ‘lack of profresionality’ because I needed to refer to some notes on a brand new talk I was giving. I thought it’d be better for me to have some form of script than try and unprofessionally ‘wing it’.</p>
<p>The other reason is that I know developers far better than me that should be talking. I’m happy to listen. I’ve set up <a href="http://www.twitter.com/LDN_Sass">LDN Sass</a> so I can listen.</p>
<p>Going back to the quote at the start of this post, and echoing Alice Bartlett’s recent post on what makes <a href="http://alicebartlett.co.uk/blog/audiencehood">a good audience member</a>.</p>
<blockquote>
<p>“…if you’re going to hop on twitter and criticise a talk, make it constructive, and if you have nothing constructive to say, then shut up.”</p>
</blockquote>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Updating My Sass Media Query Mixin</title>
      <link href="https://www.alwaystwisted.com/articles/updating-my-sass-media-query-mixin.html"/>
      <updated>2015-03-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/updating-my-sass-media-query-mixin.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in April 2013, I wrote about my <a href="../post.php%EF%B9%96s=2013-04-01-my-media-query-mixin.html">media query mixin</a> and how I wanted to keep it simple yet adaptable to most of my needs.</p>
<p>I wanted it so that I can change from min-width to max-width easily, to also use height, to make sure it’s computed in ems and not be tied down to any variables. The last one still holds true. I believe we should be still adopting the <a href="http://www.twitter.com/stephenhay">Stephen Hay</a> approach I <a href="../post.php%EF%B9%96s=2012-04-28-a-common-set-of-breakpoints-to-start.html">mentioned in 2012</a>:</p>
<blockquote>
<p>“Start with the small screen first, then expand until it looks like shit. Time to insert a breakpoint!”</p>
</blockquote>
<h2 id="moving-forward" tabindex="-1">Moving forward</h2>
<p>Since September (2014) I’ve been lucky enough to hold the role as an editor for SitePoint. Specifically their Sass channel. One of the great pleasures of doing this is reading other peoples articles on Sass and learning new things. It’s great.</p>
<p>Recently <a href="http://hugogiraudel.com/">Hugo</a> (you know him? He writes <a href="https://github.com/HugoGiraudel/awesome-sass">quite a bit</a> about Sass) <a href="http://www.sitepoint.com/breakpoints-tweakpoints-sass/">wrote an article</a> about using breakpoints and <a href="https://adactio.com/journal/6044">tweakpoints</a> in Sass which I really enjoyed reading and editing.</p>
<p>I’ve wanted to adapt the media query mixin he created to include my own ‘needs’ since and have managed to squeeze some time out of the day to create it.</p>
<h2 id="mash-it-up" tabindex="-1">Mash it up</h2>
<p>Essentially it’s a ‘mash-up’ of both mixins. It takes what is the media query I’ve been using for two years as it’s inner workings:</p>
<p>@mixin mq($point, $IE9: false, $query1: min, $query2: width) {
@if $IE9 == true{
.lt-ie9 &amp; {
@content;
}
}
@media (#{$query1}-#{$query2}: $point / $doc-font-size +em) {
@content;
}
}</p>
<p>From Hugo’s new tweakpoints and breakpoints media query it’s using the <code>@if</code> and <code>@else if</code> statements. It’s a little more verbose as a mixin and now requires me to possibly have global variables for breakpoints but it also allows me to have granular, component based tweakpoints as <a href="rethinking-your-sass-variables.html">I discussed in a recent article</a>.</p>
<p>My new Sass media query mixin now looks like this:</p>
<p>@mixin sassifaction-mq($point, $query1: min, $query2: width, $ie: false) {
@if map-has-key($tweakpoints, $point) {
@if $ie == true{
.lt-ie9 &amp; {
@content;
}
}
@media (#{$query1}-#{$query2}: map-get($tweakpoints, $point) / $sassifaction-font-size + 0em) {
@content;
}
}
@else if map-has-key($breakpoints, $point) {
@if $ie == true{
.lt-ie9 &amp; {
@content;
}
}
@media (#{$query1}-#{$query2}: map-get($breakpoints, $point) / $sassifaction-font-size + 0em) {
@content;
}
}
@else {
@warn 'Could not find the value <code>#{$point}</code> in either local ($tweakpoints) or global ($breakpoints) contexts. Media block omitted.';
}
}</p>
<p>So here, as per Hugo’s mixin we’re looking for a local <code>$point</code> in <code>$tweakpoints</code> and if there’s not one available from that Sass map the mixin will then look for a global <code>$point</code> in <code>$breakpoints</code> and finally failing silently with a <code>@warn</code> notice if neither are available.</p>
<p>Unlike Hugo’s mixin I’m converting my media to ems still, although pretty much a moot point now as <a href="http://blog.cloudfour.com/the-ems-have-it-proportional-media-queries-ftw/">proportional media queries</a> work with both <code>px</code> and <code>em</code>. I’m sticking with declaring them in ems so I know it can work on as many browsers as possible.</p>
<h2 id="the-best-of-both-worlds" tabindex="-1">The best of both worlds</h2>
<p>I’m pretty happy with what I’ve got now. I’ve got the increased option of modularity with components I create and the ability to define what type of media query I’m using (up to a point). I’ve also created it’s own litle <a href="https://github.com/sturobson/sassifaction-mq">Github Repo</a> where I’m trying to work out how to get it working with bower, ruby gems and the forthcoming <a href="https://github.com/sass-eyeglass/eyeglass">eyeglass</a> too. A work in progress, that side of the development is, thus far.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Organising Your Grunt Tasks</title>
      <link href="https://www.alwaystwisted.com/articles/organising-your-grunt-tasks.html"/>
      <updated>2015-02-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/organising-your-grunt-tasks.html</id>
      <content type="html">
        <![CDATA[
        <p>I've been slowly and steadily working on <a href="https://github.com/sturobson/squealer">Squealer</a> in my spare time and evenings recently. Trying to create a set of 'starter files using <a href="http://www.gruntjs.com">Grunt</a>. Squealer isn't really a new project. I did have a very old 'first attempt' at something using Grunt when the task runner was pretty fresh to the industry.</p>
<p>One thing I didn't like about it was the huge Gruntfile.js I was creating at the time, luckily this is something I was able to address in this iteration. Instead of <a href="http://www.html5rocks.com/en/tutorials/tooling/supercharging-your-gruntfile/">spitting out</a> all of the plugins code into one file I could simply abstract them out into their own separate .js file.</p>
<p>Now my Gruntfile.js is simply</p>
<p>module.exports = function (grunt) {
'use strict';
require('load-grunt-config')(grunt);
require('time-grunt')(grunt);
};</p>
<p>Using this I now have a folder, called grunt, where I store these separate .js files which gets pulled in. What I have to work with this now is a <a href="https://github.com/sturobson/squealer/blob/master/grunt/aliases.yml">aliases.yml file</a> that contains several options when using Grunt.</p>
<h2 id="not-just-javascript-and-sass" tabindex="-1">Not Just JavaScript and Sass</h2>
<p>I don't just want my Grunt task runner to compile Sass, uglify JS and minify all the things. The great thing with Grunt (and Gulp and others too) is the great plugins directory that is available. I've got plugins for image optimisation, for sprite generation, performance tests, creating a styleguide, prefixing CSS with vendor prefixes and more.</p>
<p>I don't really want to run 'all the things' I've got in my task runner running at the same time. Do I really need to be making sure I optimise every image I include whilst I'm developing the site, or can that wait? Do I need CSS file size calculations everytime I change something in Sass that gets compiled? Do I <em>really</em> need all the vendor prefixes when I'm using a browser that supports 99% of what I use, even CSS3 animations? What about generating that styleguide, does that have to happen on each new Sass partial created?</p>
<h2 id="don't-run-everything-all-at-once" tabindex="-1">Don't run everything all at once</h2>
<p>Essentially the answers' no. Running everything at the same time will make things slower and waste a little bit of time. The great thing about that .yml file is I can easily split out the plugins I've included so I can choose and run some of the plugins at the same time. For example, when I'm developingg I only really want be compiling my Sass and Jade files. Minifying CSS and JavaScript files can wait. Optimising images can wait.</p>
<p>I won't be keeping an eye on the CSS file size and performance statistics every waking hour so they're in a separate task to when I'm creating the styleguides from my Sass partials. I'm probably going to only optimise my images on their own once in while or nearing the end of project before it gets on any server. So that task won't be included in a set of tasks to clean and minify my JavaSript and CSS including removing any unused CSS and creating a stylesheet for Internet Explorer 8 and below.</p>
<p>Currently I have groups of tasks for:</p>
<ul>
<li><a href="https://github.com/JamieMason/grunt-imageoptim">optimising images</a>.</li>
<li><a href="https://github.com/nDmitry/grunt-autoprefixer">prefixing CSS</a>, adding <a href="https://www.npmjs.com/package/grunt-px-to-rem">REMS to any PX</a> value, changing any URLs in CSS for the dev folder.</li>
<li>creating a stylguide from the 'MarkDown' in the Sass file.</li>
<li>cleaning and minifying JavaScript and CSS.</li>
<li>testing <a href="https://github.com/phamann/grunt-css-metrics">CSS metrics</a> before and after using <a href="https://github.com/addyosmani/grunt-uncss">UnCSS</a> to see any improvements.</li>
<li>a 'dev' build for compiling Sass, generating a <a href="https://www.npmjs.com/package/grunt-stripmq">stylesheet for older browsers</a> watching and pushing changes to browsers.</li>
</ul>
<p>It's not an exhaustive list but it allows for more specific development making any compile times that little bit quicker when working in the guts of a website: The HTML, CSS and JavaScript.</p>
<h2 id="making-it-work" tabindex="-1">Making it work</h2>
<p>The 'framework' <a href="https://github.com/sturobson/squealer">Squealer</a> is still a work in progress. The YAML file containing the grunt plugins tasks will be changing to make it more 'specific' to tasks needing to be run. I've a few more plugins I want to include too. Bower is something I need to look at to call in things like jQuery and put it where it's needed in the folder structure.</p>
<p>Hopefully from this you've seen a nice logical jump to abstracting your Grunt plugins into separate files and also benefit in splitting out the tasks you need to run into separate groups as needed.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Rethinking Your Sass Variables</title>
      <link href="https://www.alwaystwisted.com/articles/rethinking-your-sass-variables.html"/>
      <updated>2015-02-26T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/rethinking-your-sass-variables.html</id>
      <content type="html">
        <![CDATA[
        <p>Using variables in Sass or any other preprocessor makes it easier to populate your stylesheets easily without having to remember the exact hexadecimal code for the <a href="http://www.lukew.com/ff/entry.asp?1469">Facebook blue 261 times</a>.</p>
<p>As well as making it easier on the developer to use something like <code>$brand-color--primary</code> instead of <code>#D37E4A</code> using a variable means if you need to change the shade of your clients main brand colour by a smidgen across the site, it's relatively easy to do so.</p>
<p>This is all good, but can we take our variables partial too far. Listening to an episode of <a href="http://www.shoptalkshow.com/episodes/153-mark-otto/">The ShopTalk Show</a> where <a href="http://www.css-tricks.com/">Chris</a> and <a href="http://www.daverupert.com/">Dave</a> talk to <a href="http://www.markdotto.com/">Mark Otto</a>, amongst other things, about <a href="http://www.getbootstrap.com/">Bootstrap</a>. At some point Mark mentions that the <a href="https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss">variable partial</a> in the UI library has around <a href="https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss#L862">860 lines</a> and that navigating it can be a bit laborious because it's so long.</p>
<p>My, pretty basic, <a href="https://github.com/sturobson/Sassifaction/blob/master/sass/_variables.scss">Sass variable partial</a> is only 80 lines or so. Not huge by any means but they're still all in one place.</p>
<h2 id="patterns" tabindex="-1">Patterns</h2>
<p>After reading <a href="https://twitter.com/ianfeather">Ian Feather's</a> article on <a href="http://ianfeather.co.uk/what-we-would-change-about-rizzo/">what Lonely Planet would change</a> about <a href="https://github.com/lonelyplanet/rizzo">Rizzo</a> I created a new repo, <a href="https://github.com/sturobson/patterns">patterns</a>, where hopefully overtime I'll include sanitised patterns used in projects, that include the relevant HTML, CSS (probably Sass) and JavaScript (if needed).</p>
<p>It's probably re-inventing the wheel a little as there's already projects like <a href="http://getbootstrap.com/">Bootstrap,</a>, <a href="http://foundation.zurb.com/">Foundation</a>, <a href="http://refills.bourbon.io/">Refills</a> that include ready made components and patterns to use but as I've <a href="../post.php%EF%B9%96s=2014-02-27-codelicious.html">previously mentioned</a> I'd 'be happy in the knowledge of what every line of code I produce is doing'' and the idea of patterns is that I only really have to do the main bulk of the coding once.</p>
<h2 id="base-and-component-variables" tabindex="-1">Base and Component Variables</h2>
<p>After reading <a href="https://twitter.com/hugogiraudel">Hugo's</a> article on <a href="http://www.sitepoint.com/breakpoints-tweakpoints-sass/">Breakpoints and Tweakpoints in Sass</a> on <a href="http://www.sitepoint.com/">SitePoint</a> where he shows a <em>really</em> neat idea in creating a CSS Media Queries mixin to allow for 'global' breakpoints that are more suited to overall layout decisions and component based breakpoints, <a href="https://adactio.com/journal/6044">'tweakpoints'</a> for 'polishing the look and feel of the page''.</p>
<p>I've been thinking this would work really well for other variables too. To have a (small) list of variables for site wide values like font families, colours, gutters, and so on which can either be called into a component with it's own variables which would then allow those component variables to be overridden.</p>
<p>For example, we would have a main variables file:</p>
<p>//  Default Variables
//  --------------------</p>
<p>$brand-color--primary: #C69;
$brand-color--secondary: #699;
$brand-color--tertiary: #F2ECE4;</p>
<p>...</p>
<p>And then we would have a component variables file. Something like:</p>
<p>//  Tabs Pattern
//  -------------------</p>
<p>$tabs-navigation-border-color: $brand-color--secondary;
$tabs-navigation-text-color: $brand-color--tertiary;</p>
<p>$tabs-main-background-color: $white;</p>
<p>...</p>
<p>Here we would have the various variables relating to the pattern named to match the pattern. This can take in variables from our global file <code>$tabs-navigation-text-color</code> using <code>brand-color--tertiary</code> for example. It also gives you the option to override and replace the global variable with whatever is required.</p>
<h2 id="nothing-is-new" tabindex="-1">Nothing Is New</h2>
<p>Having decided upon creating 'component' and 'global' variables over the last couple of weeks I often felt that this idea cannot be new. There must be another front-end developer, agency, or software company that has been 'rolling their Sass' like this for quite a while.</p>
<p>After a <a href="https://twitter.com/StuRobson/status/569181837500792832">quick tweet</a> to Mark last night consultant front-end architect <a href="http://www.csswizarday">Harry Roberts</a> <a href="https://twitter.com/csswizardry/status/569182273242832897">replied</a> saying that this is an idea he has been employing in <a href="https://github.com/inuitcss">Inuit</a> for a while now.</p>
<p>You could argue that this just takes things a little too far, but I think it makes sense. Rather than going through a document of 800 or so variables to see the <code>$jumbotron-border-color</code> is the same as the <code>$brand-color--primary</code> at the top of that file seems a little laborious and having the variable for a 'Jumbotron' component within the rest of the CSS makes it much to check and to edit if need be.</p>
<h2 id="turn-and-face-the-change" tabindex="-1">Turn And Face The Change</h2>
<p>There's a chance I might change my mind on this. The underlying idea around <a href="http://www.github.com/sturobson/patterns">patterns</a> is for me to have some 'go to' code for client projects so that I don't have to reinvent my wheel on each project.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>LDN_Sass</title>
      <link href="https://www.alwaystwisted.com/articles/ldnsass.html"/>
      <updated>2014-07-24T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/ldnsass.html</id>
      <content type="html">
        <![CDATA[
        <p>So, this morning I was looking through my twitter feed (I'm on twitter quite a bit) and I saw tweets about how well a <a href="https://twitter.com/themixinsf">Sass meetup</a> in San Francisco went (and that most attendees were signed up to <a href="https://twitter.com/sassnews">SassNews</a>).</p>
<p>I've always wanted to run some form of local meetup. In Salisbury there's not really much of 'a scene' as far as I know. Being a huge fan of Sass what I really wanted was a Sass meetup to go to.</p>
<p>So, taking the bull by the horns and after a flurry of DMs with friends that ran conferences and meetups I've decided to throw my hat in the ring.</p>
<h3 id="ldn_sass%2C-london%3F" tabindex="-1">LDN_Sass, London?</h3>
<p>As Sass is, effectively, quite a nuanced subject in web design still I've decided to hold the meetup(s) that I'm hoping to run in London. I have several developer friends in London and it's not that too far a stretch on the train.</p>
<h3 id="moving-forward" tabindex="-1">Moving Forward</h3>
<p>Obviously, I've not thought this through that greatly. I mean, the first date I picked was the day I would be flying out to Italy to speak at From The Front (<a href="http://2014.fromthefront.it/">tickets still available</a>).</p>
<h3 id="a-date" tabindex="-1">A date</h3>
<p>Wednesday the 24th of September is the date. I've decided on a Wednesday purely selfishly as this is the easiest day of the week for me to get to London and back.</p>
<h3 id="a-helping-hand" tabindex="-1">A helping hand</h3>
<p>For now I'm making the list of everything else I need. A venue, speakers, A/V equipment, food, drinks, sponsors, a nicer logo, stickers, a website(?) and probably a hundred other things that I've forgotten.</p>
<p>So, if you can help with any of the above then just get in touch. Leave a comment below, <a href="mailto:stu@alwaytwsited.com">email me</a> or ping me on <a href="http://www.twitter.com/sturobson/">twitter</a>.</p>
<p>I'm looking forward to it, as much as organising it as to spend an evening with fellow developers who use Sass.</p>
<p>For updates, for the moment it's probably best to <a href="http://www.twitter.com/LDN_Sass">follow @LDN_Sass</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Talkin&#39; &#39;bout Z-Index</title>
      <link href="https://www.alwaystwisted.com/articles/talkin-bout-z-index.html"/>
      <updated>2014-07-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/talkin-bout-z-index.html</id>
      <content type="html">
        <![CDATA[
        <p>Every now and then I see a tweet or read an article about z-index. It always bemuses me a little. I rarely find myself trying to figure out the stack of elements with z-index. Perhaps it's the work I do. I don't think that's the case because, being a jobbing freelancer, the work is forever varied.</p>
<p>I've never been a fan of z-index: 9999; the temptation just to make up long numbers to really make sure that the component will be on top is just a little too silly for my liking.</p>
<p>So, for the last 12 months or so I've been using what I call the 'Van Halen method'.</p>
<p>812
1984
5150</p>
<p>Of course, this isn't really any different from 9999, 99999 and 999999 but stipulating the numbers gives me some form of system to make sure I adhere to.</p>
<p>Taking the groups albums titles with numbers in it I've rarely, if ever, found myself needing more than these three options for z-index.</p>
<p>Of course, there's the potential in 6,9,12,24 months that I'll come back to this and laugh at myself. For the moment and for the last year, for me, it's worked perfectly.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Getting .liquid working with Emmet in Atom</title>
      <link href="https://www.alwaystwisted.com/articles/getting-liquid-working-with-emmet-in-atom.html"/>
      <updated>2014-07-04T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/getting-liquid-working-with-emmet-in-atom.html</id>
      <content type="html">
        <![CDATA[
        <p>I've been using <a href="https://atom.io/">Atom</a> for quite some time now, I managed to snag a beta invite on the day it was released and I've been enjoying seeing it improve and all the new plugins and themes that I manage to come across almost daily.</p>
<p>I do have a problem however.</p>
<p>Predominantly I use <a href="http://mixture.io/">Mixture</a> for my front-end development work. Mixture uses the <a href="http://liquidmarkup.org/">liquid language</a> to let you do <a href="http://docs.mixture.io/templates">some funky things</a>. I also like using <a href="http://emmet.io/">Emmet</a> so that I don't have to labouriously write out HTML and CSS.</p>
<p>Unfortunately the <a href="https://github.com/emmetio/emmet-atom">Emmet plugin</a> doesn't seem to <a href="https://github.com/emmetio/emmet-atom/issues/102">recognise the .liquid file type</a> and adding the liquid language plugin to Atom <a href="https://github.com/atom/language-html/pull/30">doesn't seem to do anything either</a>.</p>
<p>But I found a fix.</p>
<p>If you open your preferences in Atom (cmd + P) then filter through your installed packages for the language HTML package, open it.</p>
<p>Then guide yourself to the file called html.json which is in the folder 'grammars'.</p>
<p>At the top of the file (html.json) there will be a list of file types including HTML, SHTML, XHTML etc.</p>
<p>Follow the .json format and add 'liquid' to the bottom.</p>
<p>Save and close the file, close that window for that package.</p>
<p>Reload your project and you should find that you can now use all the emmet shortcodes and shortcuts in your liquid files.</p>
<p>Easy. Apart from this needs to be done on every update of Atom.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sass: An introduction. A workshop at WebDevConf</title>
      <link href="https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-at-webdevconf.html"/>
      <updated>2014-05-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-at-webdevconf.html</id>
      <content type="html">
        <![CDATA[
        <p>I'm really happy to finally announce I'm hosting a half day workshop for Webdevconf in Bristol in October. I've been an attendee for the last 4 years and Axex does an amazing job getting everything running smoothly.</p>
<h2 id="what-will-i-learn%3F" tabindex="-1">What Will I Learn?</h2>
<p>The workshop will give you the tools and skills to make you write better CSS by applying the benefits of Sass. Using both hands-on exercises (by taking a design and coding) and tuition the workshop will cover:</p>
<ul>
<li>Options for installing Sass on your machine</li>
<li>The two syntaxes, Sass &amp; SCSS</li>
<li>Variables, mixins and includes</li>
<li>Extends and placeholders</li>
<li>Built in functions</li>
<li>Media queries &amp; nesting</li>
<li>Compass, Bourbon and other frameworks</li>
<li>Sass and front-end performance</li>
<li>And more!</li>
</ul>
<p>Please bring your laptop (hopefully with Sass installed) as this will in part be a practical workshop.</p>
<h2 id="about-the-event" tabindex="-1">About the event</h2>
<p>WDC (webdevconf) is a one day conference held in Bristol each year around the start of October. This year Alex has added workshops to the conference that run the day before. My workshop (Sass: An Introduction) will run on Thursday 9th October 2014 in the afternoon.</p>
<p><a href="http://2014.webdevconf.com/workshops/#sturobson">- Tickets are available here -</a></p>
<h2 id="testimonials" tabindex="-1">Testimonials</h2>
<p>Here are a few testimonials from previous workshop attendees.</p>
<blockquote>
<p>“Stu did a fantastic job making Sass accessible to beginners. The workshop was incredibly practical, light on preaching and heavy on pragmatism. Even an old dog like me, came away wanting to give Sass another go. Highly recommended!”</p>
<p>Alex Morris - <a href="http://www.adobe.com/">Adobe</a></p>
</blockquote>
<blockquote>
<p>“The workshop was well balanced, Stuart shared examples and got us using Sass within minutes of the workshop starting, it was a practical hands-on introduction from a clear expert. The relaxed &amp; informal setting made it a pleasure to attend. ”</p>
<p>Steve Kirkley - <a href="http://www.twitter.com/stevekirtley">@stevekirtley</a></p>
</blockquote>
<blockquote>
<p>“Stu’s knowledge of Sass and his way of explaining the ins and outs, for me, are unparalleled to anyone else I know.  Highly recommended if you are new to Sass, or are interested in increasing your understanding of this wonderful language.”</p>
<p>Nick Toye - <a href="http://www.nicktoye.co.uk/">Pixels &amp; Code</a></p>
</blockquote>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Speaking at From the Front 2014</title>
      <link href="https://www.alwaystwisted.com/articles/speaking-at-from-the-front-2014.html"/>
      <updated>2014-05-19T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/speaking-at-from-the-front-2014.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="http://www.alwaystwisted.com/blog/fromthefront.jpg" alt="from the front logo" loading="lazy" decoding="async"></p>
<p>It's safe to say I am _really_ excited about this.</p>
<p>In fact, I'm fantastically excited to announce that I'm speaking at this years From The Front in Bologna, Italy.</p>
<p>The organisers are pulling out all the stops and there's some amazing speakers already announced with more to be announced in the lead up to the event. They're keeping a tight lip, and I'm really excited to see who else I'll get to 'strut the stage' with.</p>
<p>My mind is buzzing with Indiana Jones references, I might even 'dress up'. I'm really looking forward to going to Italy not only for the conference but obviously for all that food and drink. The idea of a calzone made to order is making me salivate.</p>
<p>But I digress...</p>
<p>I'll be shouting about the ups and downs of the menagerie of HTML and CSS frameworks and boilerplates available and why you should really think about what you're using and making your code delicious, like <a href="../post.php%EF%B9%96s=2014-02-27-codelicious.html">lasagne</a>.</p>
<h2 id="some-conference-information" tabindex="-1">Some conference information</h2>
<p>From The Front, is a two day, one track conference in Bologna, Italy. Running on the 18th and 19th of September 2014. Tickets and more information are available here:</p>
<p><a href="http://2014.fromthefront.it/">http://2014.fromthefront.it/</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sass, a whistle stop tour</title>
      <link href="https://www.alwaystwisted.com/articles/sass-a-whistle-stop-tour.html"/>
      <updated>2014-03-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sass-a-whistle-stop-tour.html</id>
      <content type="html">
        <![CDATA[
        <p>On Wednesday 12th of March I thought I'd grab <a href="http://www.twitter.com/richargwiggins">Richard Wiggins</a> for a quick second pair of eyes on some designs I've been doing over the last couple of days. We chatted about it and I mentioned the tweet I saw earlier in the day about one of the speakers for the <a href="http://mkgeeknight.co.uk/">MK (Milton Keynes) Geek Night</a> he co-organises with <a href="http://www.twitter.com/davidhughes">Dave Hughes</a> having to drop out. I asked Richard if he found a replacement for the spot. He hadn't. He asked me. I had a quick think of what I could do in (around) 5 minutes and said yes.</p>
<p>As you'll all more likely know that I like Sass I thought I'd talk about that. I didn't want to do a talk about how to get up and running with Sass on your machines and get writing your first lines of code. I wanted to try and debunk some often aired views (which I hope at a later date to blog about fully).</p>
<p>I got my copy of Keynote out and started hacking away at slides I've got for my workshops and trying to tie a nice 'story' or 'adventure' together.</p>
<p>I'm truly amazed and thankful that on the even my friend <a href="http://twitter.com/bseymour">Ben Seymour</a> decided to hold his phone still for 8/9 minutes and record my talk albeit a little flustered at times.</p>
<p>Here's the audio recording of the talk</p>
<p>I've also put <a href="https://speakerdeck.com/sturobson/sass-a-whistle-stop-tour">slides on speakerdeck</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Using Sass 3.3s @at-root for piece of mind</title>
      <link href="https://www.alwaystwisted.com/articles/using-sass-33s-at-root-for-piece-of-mind.html"/>
      <updated>2014-03-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/using-sass-33s-at-root-for-piece-of-mind.html</id>
      <content type="html">
        <![CDATA[
        <p>I often discuss on this site how I like to have ‘clarity’ or ‘cleanliness’ and order when writing my CSS/Sass. I also at some points state how the browser doesn’t give two hoots about your indentation or if you're ordering things alphabetically or not.</p>
<p>In thinking about keeping my code in check to keep my sanity also I’ve just recently ‘fell in love’ with the new @at-root directive coming in Sass 3.3.</p>
<p>With CSS3 we’ve been given some fantastic options with animations. Some developers are doing some really, really excellent work demoing these possibilities. It’s fantastic, but I have a slight problem with the syntax.</p>
<p>When I’m writing my Sass/CSS for to animate an element. I’ve never been a fan of having the @keyframe syntax outside of the element I want animating. Obviously this is great because of reusability of the same @keyframe ruleset but sometimes if gives me a level of abstraction I just cannot grok, and it looks messy (not that that matters).</p>
<h2 id="in-comes-sass-3.3s-new-%40at-root-directive" tabindex="-1">In comes Sass 3.3s new @at-root directive</h2>
<p>It’s the @at-root directive. It works by ‘jumping out’ of where you nest it in your Sass to be a the top level. For example you could use it simply like this:</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">h1 </span><span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
  <span class="token atrule"><span class="token rule">@at-root</span></span> <span class="token punctuation">{</span>
    <span class="token selector">header </span><span class="token punctuation">{</span>
      <span class="token property">margin</span><span class="token punctuation">:</span> 0 auto<span class="token punctuation">;</span>
      <span class="token property">width</span><span class="token punctuation">:</span> 98%<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Which would print out the resulting CSS like this:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">h1</span> <span class="token punctuation">{</span>
  <span class="token property">font-size</span><span class="token punctuation">:</span> 16px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">header</span> <span class="token punctuation">{</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 0 auto<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 98%<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>One quick thing to note on this is that it prints whatever is in the @at-root after rather than before where it’s been nested.</p>
<p>Since seeing this it’s taken me a while to work out where I’d find a use for it. Which brings us back to animations.</p>
<p>So, perhaps you’re making some things on your site animate. It’d be awesome if you could include those @keyframes when you’re writing the calls to it in your CSS right? You can’t because it won’t get recognised as @keyframes need to be outside, at the root of the CSS.</p>
<h2 id="at-the-root-of-the-css" tabindex="-1">At the root of the CSS</h2>
<p>Let’s for examples sake say we want to animate the scale of an avatar when visitors hovered over it. So you would write your CSS for the .avatar, something like this.</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.avatar </span><span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>
  <span class="token selector"><span class="token parent important">&amp;</span>:hover </span><span class="token punctuation">{</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> sizeme 0.8s infinite ease-in alternate<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>For this we’d then need to make some @keyframes for sizeme so that it works. Something (ridiculous for example) like this.</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@keyframes</span> fade</span> <span class="token punctuation">{</span>
  <span class="token selector">0%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">25%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">50%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">75%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">100%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Ok, but how about adding that @keyframe into the SCSS rather than outside it so it’s ‘together’. Well, with Sass 3.3s new @at-root directive you can write something like this.</p>
<pre class="language-scss"><code class="language-scss"><span class="token selector">.avatar </span><span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>

  <span class="token atrule"><span class="token rule">@at-root</span></span> <span class="token punctuation">{</span>
    <span class="token atrule"><span class="token rule">@keyframes</span> fade</span> <span class="token punctuation">{</span>
      <span class="token selector">0% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token selector">25% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token selector">50% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token selector">75% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token selector">100% </span><span class="token punctuation">{</span>
        <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token selector"><span class="token parent important">&amp;</span>:hover </span><span class="token punctuation">{</span>
    <span class="token property">animation</span><span class="token punctuation">:</span> fade 0.8s infinite ease-in alternate<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>And it would print out CSS like this</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.avatar</span> <span class="token punctuation">{</span>
  <span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
  <span class="token property">height</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>
  <span class="token property">margin</span><span class="token punctuation">:</span> 40px<span class="token punctuation">;</span>
  <span class="token property">width</span><span class="token punctuation">:</span> 120px<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token atrule"><span class="token rule">@keyframes</span> fade</span> <span class="token punctuation">{</span>
  <span class="token selector">0%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">25%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">50%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">75%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.2<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token selector">100%</span> <span class="token punctuation">{</span>
    <span class="token property">transform</span><span class="token punctuation">:</span> <span class="token function">scale</span><span class="token punctuation">(</span>1.1<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token selector">.avatar:hover</span> <span class="token punctuation">{</span>
  <span class="token property">animation</span><span class="token punctuation">:</span> fade 0.8s infinite ease-in alternate<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>So that the animation works. You could also use the @at-root for something like @supports too.</p>
<p>Here's a <a href="http://sassmeister.com/gist/9408093">gist of the example above</a> on Sassmeister.</p>
<p>What ways can you think of that’d be a great use of the new @at-root?</p>
<hr>
<p>So you obviously love Sass. So how about <a href="http://eepurl.com/ErvvT">signing up to a weekly newsletter</a> of all things Sass direct to your inbox, curated by me?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Even Better @each loops with Sass 3.3</title>
      <link href="https://www.alwaystwisted.com/articles/even-better-each-loops-with-sass-33.html"/>
      <updated>2014-03-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/even-better-each-loops-with-sass-33.html</id>
      <content type="html">
        <![CDATA[
        <p>In the not to distant future Sass 3.3 is going to land for the masses outside of it’s pre-release cycle. I’ve already discussed how they’ve now made things like <a href="../post.php%EF%B9%96s=2014-02-27-even-easier-bem-ing-with-sass-33.html">BEM in your CSS even easier</a>. So I’d thought I’d touch on something else that’s on it’s way that’s pretty Sass-y.</p>
<p>With Sass 3.2 you can easily generate some CSS based on a list of ‘things’. Perhaps you wanted to have some social links on a site and wanted to have the background of each relevant link the association colour of that social network.</p>
<p>You’d probably make some variables like this to start with:</p>
<p>$Twitter: #41b7d8;
$FB: #3b5997;
$GPlus: #d64937;
$LinkedIn: #0073b2;</p>
<p>You could then add these into a list ready to be pulled into the @each loop:</p>
<p>$social-colours: $Twitter, $FB, $GPlus, $LinkedIn;</p>
<p>You’d then write some Sass like this to get the @each to loop through the list and generate the relevant CSS:</p>
<p>li {
float: left;
height: 48px;
list-style: none;
width: 100%;
}
@for $i from 1 through length($social-colours) {
li:nth-of-type(#{$i}) {
background: nth($social-colours, $i);
}
}</p>
<p>That in turn, when printed out would give a result like this:</p>
<p>ul li {
float: left;
height: 48px;
list-style: none;
width: 100%;
}
ul li:nth-of-type(1) {
background: #41b7d8;
}
ul li:nth-of-type(2) {
background: #3b5997;
}
ul li:nth-of-type(3) {
background: #d64937;
}
ul li:nth-of-type(4) {
background: #0073b2;
}</p>
<p>That in itself is pretty cool right? You may want to add another link at a later date. All you’ve gotta do is tap on another colour (or $variable) at the end and it’d get printed out in your CSS.</p>
<h2 id="but-we-want-more-than-one-thing-in-the-list" tabindex="-1">But we want more than one thing in the list</h2>
<p>As you can see from the example above I’ve used nth-of-type to style each li differently. What if I wanted to give my li a class of the relevant social network? Perhaps I want to add an icon in each li too?</p>
<p>Well you could create more lists, but that can be a bit cumbersome and isn’t as tidy as answer.</p>
<p>With Sass 3.3 you have the ability to have can create a list of lists and then use the @each directive to make some Sass-y outputted CSS.</p>
<p>So going back to our crude example. Rather than use nth-of-type let’s give each printed li it’s own class name relevant to the social network.</p>
<p>Keeping our original set of variables above we could then make a new list like this:</p>
<p>$social: (twitter, $Twitter),
(facebook, $FB),
(googleplus, $GPlus),
(linkedin, $LinkedIn);</p>
<p>So above you can see from a glance what’s going on, nice and simple. Now lets uses those lists in the list to create some CSS.</p>
<p>@each socialnetwork, color in $social { }</p>
<p>Here we’ve given the two lists in the list social their own variable to be called upon in the curly braces. Let’s add more code.</p>
<p>@each $socialnetwork, $color in $social {
.social-link--#{$socialnetwork} {
background-color: $color;
&amp;:focus,
&amp;:hover {
background-color: darken($color,5%);
}
}
}</p>
<p>So here we’ve used the color as before but added the social network into the classname. This prints out some CSS like this:</p>
<p>.social-link--twitter {
background-color: #41b7d8;
}
.social-link--twitter:focus,
.social-link--twitter:hover {
background-color: #2cafd4;
}</p>
<p>.social-link--facebook {
background-color: #3b5997;
}
.social-link--facebook:focus,
.social-link--facebook:hover {
background-color: #344e85;
}</p>
<p>.social-link--googleplus {
background-color: #d64937;
}
.social-link--googleplus:focus
.social-link--googleplus:hover {
background-color: #ca3c29;
}</p>
<p>.social-link--linkedin {
background-color: #0073b2;
}
.social-link--linkedin:focus
.social-link--linkedin:hover {
background-color: #006399;
}</p>
<p>That’s pretty cool. Generating some tidy CSS through the new @each directive. You could then perhaps add a background icon if you wanted too. Just simply add another line of code to the example:</p>
<p>@each $socialnetwork, $color in $social {
.social-link--#{$socialnetwork} {
background-color: $color;
&amp;:focus,
&amp;:hover {
background-color: darken($color,5%);
}
&amp;:before {
background-image: url('/images/#{$socialnetwork}.png');
}
}
}</p>
<p>We’re getting somewhere nice and awesome here and this is just a quick example. I’m really looking forward to 3.3 dropping for real. I think it’s pretty stable at the moment to give it a whirl. Don’t forget it’s now available in <a href="http://www.codepen.io">CodePen</a> and <a href="http://www.sassmeister.com">Sassmeister</a>.</p>
<p>The example above is <a href="http://sassmeister.com/gist/9378629">available here</a> to peruse and pick apart</p>
<p>How do you think you can make use of the new lists within lists @each directive?</p>
<hr>
<p>So you obviously love Sass. So how about <a href="http://eepurl.com/ErvvT">signing up to a weekly newsletter</a> of all things Sass direct to your inbox, curated by me?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>My Shed</title>
      <link href="https://www.alwaystwisted.com/articles/my-shed.html"/>
      <updated>2014-02-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/my-shed.html</id>
      <content type="html">
        <![CDATA[
        <p>More often than not I probably open a new <a href="http://codepen.io/">CodePen</a> at least 20-30 times a day. I don’t keep count. That’d be silly.</p>
<h2 id="i-%3C3-codepen" tabindex="-1">I &lt;3 CodePen</h2>
<p>If I need to quickly thrash out how I’m going to code something I jump straight into CodePen before I open an IDE. If someone on twitter asks a Sass/CSS question I open a new pen to play with it for a minute or two. <a href="http://codepen.io/sturobson/">I frickin’ love CodePen</a>.</p>
<h2 id="my-shed" tabindex="-1">My Shed</h2>
<p>It’s become my (digital) <a href="http://hicksdesign.co.uk/journal/the-shed">‘shed’</a>. Where I go to and tinker with and fettle code whether I need it for a project or just for fun.</p>
<h2 id="great-for-clients" tabindex="-1">Great for clients</h2>
<p>Going back to last October I was working on a site for a client in London. There were quite a few interactions on the pages that needed to be animated when the visitor hovered over them.</p>
<p>I instantly thought that by making a private CodePen (available with <a href="http://codepen.io/pro">a Pro account</a>) of each interaction I could then send them to the client for feedback. I was given a pdf of what each interaction should do, what should slide, move, animate and change colour etc. I then turned my interpretation of those descriptions into some lovely Sass-ified CSS for each one.</p>
<p>The client seemed really pleased with the idea of these ‘tiny little bootstraps’ and it made working out what they wanted into a reality so easy.</p>
<h2 id="get-a-shed" tabindex="-1">Get a shed</h2>
<p>If you’re not using CodePen I suggest you do. It’s so good to have your own shed.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>How I use my RSS</title>
      <link href="https://www.alwaystwisted.com/articles/how-i-use-my-rss.html"/>
      <updated>2014-02-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/how-i-use-my-rss.html</id>
      <content type="html">
        <![CDATA[
        <p>Last night at the Port80 spring #Localhost I touched on ways I ‘keep up’ in web development, now I’m working full-time in the industry instead of being on the peripherals as a night-owl freelancer.</p>
<p>After twitter, which I use once in a while, I rely on my collection of RSS feeds.</p>
<p>I’ve got around 400+ feeds hooked up to my feedbin account. Indeed that is a serious amount of feeds that can lead to a potentially huge number of posts at any given time I check.</p>
<h2 id="if-it-sounds-boring%2C-i%E2%80%99d-guess-it-is" tabindex="-1">If it sounds boring, I’d guess it is</h2>
<p>As I’ve got a potential huge amount of posts to go through I ‘attack’ my RSS in 3 stages.</p>
<p>First off I go through the whole list and then ‘mark as read’ any posts where the title doesn’t interest me. A little harsh but I don’t think this has affected my reading up on things over the last year or so.</p>
<p>Secondly, after I’ve done this I generally open up each post that’s left and have a quick skim read. If it still seems interesting I think ‘mark as unread’ to read later. Which is basically step 3.</p>
<h2 id="but-that-still-takes-time" tabindex="-1">But that still takes time</h2>
<p>Of course, at the end of the day, this still takes time. I find time though. Be it those few minutes before I fall asleep in bed (when the iPhone whacks me on the head) or waiting for the kettle to boil for a nice cup of joe.</p>
<h2 id="tweeting-what-i-like" tabindex="-1">Tweeting what I like</h2>
<p>If time is on my side I often go through a tweeting spree of posts that I read in step 3 that I hope people that follow me would find interesting too.</p>
<h2 id="%23fastidious" tabindex="-1">#fastidious</h2>
<p>So to get me to read your post first off I need an interesting title, fastidious I know.</p>
<p><a href="https://www.dropbox.com/s/d0e22k6mn2w4ikz/RSS.xml">Here’s a link to my current collection of RSS feeds as an XML file</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Even Easier BEM-ing with Sass 3.3</title>
      <link href="https://www.alwaystwisted.com/articles/even-easier-bem-ing-with-sass-33.html"/>
      <updated>2014-02-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/even-easier-bem-ing-with-sass-33.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in October last year (2013) <a href="http://blog.unakravets.com/post/64113156740/sass-3-3-at-root-bem">Una wrote a blog post</a> about using Sass 3.3s new @at-root directive to create some sexy easy BEM nesting possibilities.</p>
<p>BEM (Block, Element, Modifier) from <a href="http://bem.info/method/">Yandex</a> allows developers to create a simple naming convention helping make your CSS more modular and portable.</p>
<p>.block{} // the ‘thing’ like .list
.block__element{} // a child of the block like .list__item
.block--modifier{} // a variation of the ‘thing’ like .list-—vertical</p>
<p>Using the way Una described you would write some Sass like this ...</p>
<p>.block {
@at-root #{&amp;}__element {
}
@at-root #{&amp;}--modifier {
}
}</p>
<p>... which would print out like this ...</p>
<p>.block {}
.block__element {
}
.block--modifier {
}</p>
<p>When Sass 3.3.0rc3 came out a couple of weeks ago they changed this. For the better. <a href="http://www.twitter.com/nex3">Natalie</a> explains the goings on in <a href="http://nex3.roughdraft.io/8050187">this gist</a> (via <a href="http://jedfoster.com/">Jed Fosters</a> <a href="http://www.roughdraft.io/">roughdraft.io</a>).</p>
<p>Now instead of needing ugliness of @at-root #{&amp;} which in honesty was putting me off, you can now just use the ampersand. This makes your Sass look so much nicer (not that <em>that</em> matters) and quicker to write, obviously.</p>
<p>So now you would write some Sass like this ...</p>
<p>.block {
&amp;__element {
}
&amp;--modifier {
}
}</p>
<p>... which now prints out like this ...</p>
<p>.block {}
.block__element {
}
.block--modifier {
}</p>
<p>I’m sure you can see how even sassier your Sass looks and the results remain the same.</p>
<p>For a ‘real world’ case of showing this technique and using BEM let’s have a look at some main navigation HTML</p>
<p><nav role='navigation' aria-label='primary'>
<ul class='nav__list'>
<li class='nav__list__item'>
<a href='' class='nav__link'></a>
</li>
<li class='nav__list__item'>
<a href='' class='nav__link--active'></a>
</li>
<li class='nav__list__item'>
<a href='' class='nav__link'></a>
</li>
</ul>
</nav></p>
<p>we could then write some Sass like this (being all BEM’y I’ve not added a class to the main nav (through personal choice)) ...</p>
<p>nav[role=navigation] {}
.nav {
&amp;__list {
&amp;__item {
}
}
&amp;__link {
&amp;--active {
}
}
}</p>
<p>You’d get this result.</p>
<p>nav[role=navigation] {
}
.nav {
}
.nav__list {
}
.nav__list__item {
}
.nav__link {
}
.nav__link--active {
}</p>
<p>That’s pretty sweet if you ask me, makes Sass nesting work nicely without giving too much to the inception rule to worry about. I’ve also gone on to make a version of <a href="http://sassmeister.com/gist/9228656">Harry Roberts’ Beautons</a> using it too.</p>
<p>What examples can you think of that this would be great for?</p>
<hr>
<p>So you obviously love Sass. So how about <a href="http://eepurl.com/ErvvT">signing up to a weekly newsletter</a> of all things Sass direct to your inbox, curated by me?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>#codelicious</title>
      <link href="https://www.alwaystwisted.com/articles/codelicious.html"/>
      <updated>2014-02-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/codelicious.html</id>
      <content type="html">
        <![CDATA[
        <p>I love lasagne.</p>
<p>I can probably hazard a guess that it's actually because of Garfield that I love lasagne.</p>
<p>My mum made a mean lasagne. When I started to cook I think lasagne was one of the first three dishes I learned to cook. Whenever I've been out for a pub lunch that's not on any given Sunday I generally choose lasagne. Some are great, others not so much.</p>
<p>I make a mean lasagne. But it's a different to the lasagne my mum makes. I don't use a the herbs she does and I add half a tea spoon extra of balsamic vinegar. I also put a more than necessary amount of cheese on top.</p>
<p>You see with lasagne there's many ways you can make it a mean, lean tummy-filling machine and that, for me, is a great thing. It's why I love lasagne.</p>
<h2 id="wha--%3F" tabindex="-1">Wha- ?</h2>
<p>But what's this got to do with modern web development?</p>
<p>Well, I probably write code slightly differently to you. I use the margin and padding short-hand but not the font or background short-hand. I order my CSS rules alphabetically and order my SCSS rules in a certain way.</p>
<p>Yes, it all gets compiled and gzipped to a barely readable file when it goes live but that’s because the browser doesn’t care how you originally wrote it.</p>
<p>Using your own ‘framework’ or ‘boilerplate’ is the best way to hone your skill-set and improve for not only your benefit, but your clients and their customers.</p>
<p>It seems like so many new boilerplates, starting points and frameworks are being released it can seem to easy just to use something ‘off the shelf’. I seriously think this would be an injustice to yourself.</p>
<h2 id="the-starting-point" tabindex="-1">The starting point</h2>
<p>I guess we could say that the HTML5 boilerplate was the first, well ‘boilerplate’ for developers to quickly grab and hit the ground running with. It came with predefined ways of ‘doing things’ and a lovely <a href="https://github.com/h5bp/html5-boilerplate/issues/610">shade of pink</a> for when touching or selecting an element.</p>
<p>It still allowed developers to adapt and change to their own melt but invariable some used it verbatim without worrying or wondering why things were written in a certain way or even why they’re there to begin with.</p>
<h2 id="progressive-cookie-cutting" tabindex="-1">Progressive cookie cutting</h2>
<p>Moving forward developers took the idea of the boilerplate and expanded it, making things like <a href="http://getbootstrap.com/">Bootstrap</a> or <a href="http://foundation.zurb.com/">Foundation</a>. Coming along with some predefined objects and styles meant front-end developers could quickly flesh out a site with modules all ready to go.</p>
<h2 id="not-my-style" tabindex="-1">Not My Style</h2>
<p>I just can not do this. I’d much <a href="http://github.com/sturobson/Sassifaction">rather re-invent the wheel</a> a little and be happy in the knowledge of what every line of code I produce is doing even, for example, if I’m leaving Sass to do it’s ‘magic’ without worrying how’s its doing so.</p>
<p>I prefer to write my own mixins that suite my needs, code in a style that works with my (unfortunately, soon to be) cue ball noggin understanding it.</p>
<h2 id="beg%2C-borrow-and-steal" tabindex="-1">Beg, borrow and steal</h2>
<p>Don’t get me wrong, I often don’t write ‘everything’ uniquely without prior knowledge of things. Fundamentally I look through other starting points and frameworks see something that piques my interest and often drop it into my own set of starting files.</p>
<p>I’m just ‘careful’ or picky (or opinionated) in what I want to include and what I don’t.</p>
<h2 id="easier-to-take-away-than-to-add-it-after-you-launch" tabindex="-1">Easier to take away than to add it after you launch</h2>
<p>Generally, my starting point has ‘everyhing’ when I first start. I’ve got a link to respond.js in the <head>, there’s a link to the full latest Modernizr script and so on.</p>
<p>I find it easier to take away the things I don’t need as I move through developing a project rather than adding to it as needed (although there’s always a chance to add something still).</p>
<p>Many a time have I seen a new ‘responsive’ site launch that fails to work on my iPhone because they forgot to add the viewport meta tag.</p>
<h2 id="only-in-teams" tabindex="-1">Only in teams</h2>
<p>Anything you do with your starting point should of course be documented. If you’re in a team you want everyone to be ‘singing for the same hymn sheet’. If you hand over your work to a client then providing adequate documentation about your starting point and coding style will pave the way for them to easily see what you’re doing and why.</p>
<h2 id="a-quarter-pounder-with-cheese" tabindex="-1">A quarter pounder with cheese</h2>
<p>Writing your own set of starting files means you care about the details, the simple nuances of the code you’re using, making it ‘delicious’.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Talking at Port80&#39;s Spring Localhost</title>
      <link href="https://www.alwaystwisted.com/articles/talking-at-port80s-spring-localhost.html"/>
      <updated>2014-01-26T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/talking-at-port80s-spring-localhost.html</id>
      <content type="html">
        <![CDATA[
        <p>On February the 26th I’ll be in Newport at the Port80 Spring Localhost event, organised by the Joel Hughes.</p>
<p>As well as myself you will also have chance to hear <a href="http://twitter.com/garethstrange">Gareth Strange</a> from <a href="http://twitter.com/bluegg">Bluegg</a> talk about making time for personal projects and <a href="http://twitter.com/rumyra">Ruth John</a> who works for o2 discuss all the snazziness of Web Components.</p>
<p>This will be a first for me, not only a ‘new’ talk it will also see me trying to talk about something very personal rather than something somewhat technical or opinionated.</p>
<p>I’ll be telling the story of my first year of freelancing. The highs and the lows, the bacon, the weight gain. I’m hoping it’ll be a little bit more entertaining than that.</p>
<p>I hope to share insight into how I somehow ‘make things work’ and hope that people attending will an idea or something to riff on away with them.</p>
<p><a href="http://port80events.co.uk/event/spring-localhost-2014/">More info about the event from the site.</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>An idea for smarter coding comments</title>
      <link href="https://www.alwaystwisted.com/articles/an-idea-for-smarter-coding-comments.html"/>
      <updated>2014-01-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/an-idea-for-smarter-coding-comments.html</id>
      <content type="html">
        <![CDATA[
        <p>I often write code quickly and refactor it as an on going process. I tend not to have a ‘written’ list of things that need ‘fixing’ and up until recently kept everything ‘in my head’ (a bonus of generally doing all the front-end development myelf).</p>
<p>I am currently working on an app for a client from Denmark wherein eventually the codebase will effectively ‘leave my hands’ to go to another developer to pull apart and integrate into their system.</p>
<h3 id="make-that-change" tabindex="-1">Make that change</h3>
<p>This time I thought I would start to actually write things down.</p>
<p>I could quite easily add a comment to my SCSS like this</p>
<p>height: 300px; // TODO: magic number to be removed</p>
<p>Starting all single line comments on code that needs to be fixed with the word TODO. I could then search through my project using Sublime Text (for example) and fix these things as and when before the other developers start cutting and slicing.</p>
<h3 id="make-it-easier" tabindex="-1">Make it easier</h3>
<p>I quickly got to thinking. Perhaps I could make my comments a little smarter. Rather than using the word TODO I could use a word that’s more ‘semantic’ to what needs fixing, looking at or refactoring.</p>
<p>For example I could take the above code and do this</p>
<p>height: 300px; // @magic</p>
<p>This would allude to what the comment is for, is easy to search groups of the same thing by.</p>
<p>Of course this could get tricky the more and I may need to create a glossary file of what the single worded comments mean.</p>
<p>I’m sure you can tell by the style of my writing that this is just a little brain-dump of an idea. It's probably not a even new idea.</p>
<p>(subject to change before 9am tomorrow morning and beyond.)</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Colour me Sass-y</title>
      <link href="https://www.alwaystwisted.com/articles/colour-me-sass-y.html"/>
      <updated>2014-01-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/colour-me-sass-y.html</id>
      <content type="html">
        <![CDATA[
        <p>I don’t tend to have to worry about what colours to use on a site. I generally don’t ‘design’ anymore and concentrate on coding the front-end of a project.</p>
<p>That being said, there’s times when I need to manipulate the colours I’m given in a design in the CSS. Maybe quickly make a brand colour have an alpha transparency on a overlay or some such other thing.</p>
<p>Sass helps me do this and more. The colour functions built into Sass are pretty amazingly mathematical and yet so easy to implement. In this post I’m going to quickly go through them all and mention a couple of ‘extra’ ones that are in Compass but not in Sass by default.</p>
<h3 id="darken-%26-lighten" tabindex="-1">darken &amp; lighten</h3>
<p>Two colour functions I often use when ‘playing’ around with some Sass ideas and sometime use, if appropriate, on client projects are darken and lighten. Each take the hex value of the colour (be it a hex value, rgb or $variable) you pass it, converts it into its HSL equivalent then makes the adjustments. The adjustment is declared as a percentage for these two functions.</p>
<p>.box-1 { background-color: lighten(#D13400, 30%); }
.box-2 { background-color: darken(#D13400, 30%); }</p>
<p>would give</p>
<h3 id="rgba" tabindex="-1">RGBa</h3>
<p>You can easily give the colour you’re using an alpha transparency. You give the colour you require a levle of transparency from 0 to 1.</p>
<p>.box-3 { background-color: rgba(#D13400, .6); }</p>
<p>would give an rgba color output.</p>
<h3 id="desaturate-%26-saturate" tabindex="-1">desaturate &amp; saturate</h3>
<p>These adjust the saturation (funnily enough) of the color by converting the hex value to HSL again. This like darkness and lighten requires a percentage to be passed.</p>
<p>.box-4 { background-color: saturate(#D13400, 40%); }
.box-5 { background-color: desaturate(#D13400, 40%); }</p>
<p>which gives more and less saturated colors respectively.</p>
<h3 id="complement-%26-invert" tabindex="-1">complement &amp; invert</h3>
<p>Here’s two I don’t think I’ve ever used. Again the hex colour is converted into HSL and then gets adjusted. For these you only pass the colour you’re wishing to adjust. No values or percentages.</p>
<p>.box-6 { background-color: complement($color); }
.box-7 { background-color: invert($color); }</p>
<p>would give the complementary and inverted color versions.</p>
<h3 id="adjust-hue" tabindex="-1">adjust-hue</h3>
<p>Another I can’t recall ever needing to use, again it converts the hex color value to HSL and requires a degree value(unit optional) being passed to calculate the adjustment.</p>
<p>.box-8 { background-color: adjust-hue($color, 40deg); }</p>
<p>gives a hue-adjusted color output.</p>
<h3 id="grayscale" tabindex="-1">grayscale</h3>
<p>I have never used this and struggle to figure out why one ever would, really. All the same, this (again) converts the hex to HSL creating a grayscale alternative to the color passed</p>
<p>.box-9 { background-color: grayscale($color); }</p>
<p>gives a grayscale version of the color.</p>
<h3 id="something%E2%80%99s-missing-(for-me)" tabindex="-1">Something’s missing (for me)</h3>
<p>I’ve dabbled with Compass. I don’t use it on any projects I work on as I quite like creating my own ‘things’ as much as Chris is doing a frickin’ fantastic job with it. There’s nothing I’ve missed not having when running with my own mixin library (yes, I know Compass does a (heck of a) lot more).</p>
<p>Two function I really liked in Compass that are native to Sass are tint &amp; shade. These work great for creating things like a <a href="http://www.stuffandnonsense.co.uk/archives/creating_colour_palettes.html">colour pallete</a>) so I use the following two functions to recreate what Compass gets tint and shade to do and have them in my mixin library ready to go.</p>
<p>Using the RGB mix function I can create the desired effect. Mix takes two colours and mixes them together with the given weight (percentage).</p>
<p>mix($color-1, $color-2, [$weight])</p>
<p>So if we used black and white for $color-1 we can create the tint and shade functions.</p>
<p>@function tint($color, $percent){
@return mix(white, $color, $percent);
}</p>
<p>@function shade($color, $percent){
@return mix(black, $color, $percent);
}</p>
<p>Which you would simply use like this.</p>
<p>.box-10 { background-color: tint($color, 40%); }
.box-11 { background-color: shade($color, 40%); }</p>
<p>which gives tinted and shaded color variations.</p>
<p>The tint and shade functions are found in my <a href="http://github.com/sturobson/Sassifaction/">Sassifaction</a> mixin library.</p>
<p>Like I said, I generally only use rgba, lighten, darken, tint and shade when I’m either having a play on codepen or when a project allows. It’s pretty nice and easy to only have to pass some simple information and get a hex value without having to worry about how it got there.</p>
<p>Go forth and colour yourself Sass-y.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>REMs, Fallbacks and Support</title>
      <link href="https://www.alwaystwisted.com/articles/rems-fallbacks-and-support.html"/>
      <updated>2014-01-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/rems-fallbacks-and-support.html</id>
      <content type="html">
        <![CDATA[
        <p>I’ve been using REMs for font sizing exclusively (with a fallback) since Jonathan <a href="http://www.twitter.com/snookca">Snook</a>’s article - <a href="http://snook.ca/archives/html_and_css/font-size-with-rem">font sizing with rem</a> from 2011. So I’ve been (more or less) writing out the font-size property like this.</p>
<p>.prose p {
font-size: 16px;
font-size: 1rem;
}</p>
<p>So, we’ve only got to <a href="http://caniuse.com/#search=rem">worry about supporting Internet Explorer 9 and up</a> as every modern browser in use today supports it, right? If we’re not wanting to support Internet Explorer 8 and below you could just do something like this and all the world will be happy.</p>
<p>.prose p {
font-size: 1rem;
}</p>
<p>Not necessarily. One browser that’s often missed is Opera mini.</p>
<p>Stop laughing. Here’s some numbers.</p>
<p>Tim Cook let the cat out of the bag and announced there were <a href="http://9to5mac.com/2013/10/22/tim-cook-talks-numbers-at-ipad-event-64-of-ios-devices-on-ios-7-20-million-itunes-radio-listeners-1-billion-songs-played/">170 million iPads</a> in the world. I’d quickly note that this doesn’t neccesarily mean that people are browsing the internet on those devices, but at a good guess let’s say they all are.</p>
<p>That’s a pretty big number but what’s that got to do with Opera mini?</p>
<p>Opera mini has <a href="http://www.operasoftware.com/smw/2013-11">241 million active users</a>.</p>
<p>That’s a pretty big number. Wait, that's 70 million more users than iPad owners.</p>
<p>So, if you’re going to be using REMs I think it’d be pretty wise to keep that pixel value fallback in there. I’m sure after you’ve gzip’d your CSS those additional characters will take up very little space.</p>
<h2 id="pre-processors" tabindex="-1">Pre-Processors</h2>
<p>The easiest and quickest way to always have that fallback set is using a pre-processor like <a href="#Sass">Sass</a>, <a href="#LESS">LESS</a> or <a href="#Stylus">Stylus</a>. Creating a mixin would mean you're writing less code meaning you're saving time for chocolates and such.</p>
<h3 id="less" tabindex="-1">LESS</h3>
<p>/* Set up a variable for maths */</p>
<p>@doc-font-size: 16;</p>
<p>/* the font-size mixin */</p>
<p>.font-size (@size) {
font-size: 0px + @size;
font-size: 0rem + @size / @doc-font-size;
}</p>
<p>/* example of usage */</p>
<p>.prose p {
.font-size(16);
}</p>
<p>/* example compiled */</p>
<p>.prose p {
font-size: 16px;
font-size: 1rem;
}</p>
<h3 id="sass(scss)" tabindex="-1">Sass(SCSS)</h3>
<p>/* Set up a variable for maths */</p>
<p>$doc-font-size: 16;</p>
<p>/* the font-size mixin */</p>
<p>@mixin font-size($size) {
font-size: 0px + $size;
font-size: 0rem + $size / $doc-font-size;
}</p>
<p>/* example of usage */</p>
<p>.prose p {
@include font-size(16);
}</p>
<p>/* example compiled */</p>
<p>.prose p {
font-size: 16px;
font-size: 1rem;
}</p>
<h3 id="stylus" tabindex="-1">Stylus</h3>
<p>/* Set up a variable for maths */</p>
<p>doc-font-size = 16</p>
<p>/* the font-size mixin */</p>
<p>font-size(size)
font-size: 0px + size
font-size: 0rem + (size / doc-font-size)</p>
<p>/* example of usage */</p>
<p>.prose p
font-size(16)</p>
<p>/* example compiled */</p>
<p>.prose p {
font-size: 16px;
font-size: 1rem;
}</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>2013</title>
      <link href="https://www.alwaystwisted.com/articles/2013.html"/>
      <updated>2014-01-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/2013.html</id>
      <content type="html">
        <![CDATA[
        <p>So, 2013 was my first year freelancing full time. I thought it’d be nice for me to just quickly jot some ‘statistics’ down from what’s happened since January 7th 2013.</p>
<p>Here goes...</p>
<p>This last year I’ve worked on 40 different projects. Ranging from some quick content updating of an HTML email, in both English and Welsh, to creating templates and WordPress sites.</p>
<p>With these 40 projects I’ve worked for 25 different clients. I think that’s quite a high number but it’s good to see that I’m retaining some regular clients for work now too. The start of 2014 sees me working one three projects for returning clients so hopefully it’s an upwards trend.</p>
<p>Unfortunately I’ve had two non-paying clients this year. Both were for reasonably small amounts (in my opinion) and have led me to tighten up my contract and ‘go with my gut’ rather than take any job going because I’d needed the money.</p>
<p>I’ve also had a stretch of 17 consecutive working days without any client work. It was at the start of the year and I noticed that I wasn’t ‘looking for the next gig’ as early as I’d needed to be and waiting until I’d finished one job before looking for another. This has been rectified and since July I think I’ve only had 2 consecutive days without work.</p>
<p>The shortest project took an hour to do. The longest lasted 13 working days.</p>
<p>I attended 9 conferences this year, 3 of which were online. I also attended 2 workshops and 4 evening events. I decided at the start of the year I was going to spend the first year going to as many as I could afford to and then reign myself in for 2014 and onwards. Looking at 2014 already, I don’t think that’s going to happen.</p>
<p>There’s probably some stuff I’ve missed. There’s a chance I’ll edit this post as I think upon it and add things.</p>
<p>Finally, come on 2014. Let’s be havin’ ya.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Not your average vertical rhythm Sass mixin</title>
      <link href="https://www.alwaystwisted.com/articles/not-your-average-vertical-rhythm-sass-mixin.html"/>
      <updated>2013-12-30T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/not-your-average-vertical-rhythm-sass-mixin.html</id>
      <content type="html">
        <![CDATA[
        <p>Way back when in September 2012 or so I was looking into vertical rhythm in design and layout. I instantly thought it would be great to create a Sass mixin that creates the line height and bottom margin for your typography based on the font size your pass it.</p>
<p>So I took to CodePen and created this -</p>
<p>// initial variables set-up
$doc-font-size:16;
$doc-line-height:24;
// mixin
@mixin font-size($size) {
font-size: 0px + $size;
font-size: 0rem + $size / $doc-font-size;
line-height: ceil($size / $doc-line-height) * ($doc-line-height / $size);
margin-bottom: 0px + $doc-line-height;
margin-bottom: ($doc-line-height / $doc-font-size) +rem;
}</p>
<p>This simple mixin gives the element the font-size in REM with PX fallback for OldIE and other browsers (like Opera mini). A line height based on the font-size and the document’s line height that’s set. Finally you get a bottom margin, again in REM with a PX fallback that’s defined by the documents font size and line height.</p>
<p>This gives you some sweet vertical rhythm for you site.</p>
<p>I had an itch.</p>
<p>What if I wanted an element to have no bottom margin? What if I wanted to have a bigger line-height or no line height or maybe a larger or smaller bottom margin?</p>
<p>So I took to codepen again and adapted that mixin to allow for those questions to be answered.</p>
<h3 id="so-where-is-it%3F" tabindex="-1">So where is it?</h3>
<p>It’s built in to my recently updated set of Sass mixins and files - <a href="https://github.com/sturobson/Sassifaction">Sassifaction</a>.</p>
<p>Therein it’s also built and ready in my Mixture Project - <a href="https://github.com/sturobson/Sassifaction-Mixture">Sassifaction Mixture</a>.</p>
<p>If you just want it on it’s own or have a play it’s also on <a href="http://codepen.io/sturobson/pen/fhige">CodePen</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>How I write my Sass</title>
      <link href="https://www.alwaystwisted.com/articles/how-i-write-my-sass.html"/>
      <updated>2013-12-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/how-i-write-my-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>Back at the beginning of May I added some ‘rules’ to how I write my Sass (or SCCS) on a <a href="http://github.com/sturobson/a-slightly-bizarre-starting-point">front-end project</a>.</p>
<p>I thought as I’ve just released version 2 of <a href="http://github.com/sturobson/Sassifaction">Sassifaction</a> I’d share my decisions in this blogpost to help clarify to myself how I should be writing my Sass and hopefully helping others make decisions on how they write their Sass and order things.</p>
<h2 id="at-the-beginning" tabindex="-1">At the beginning</h2>
<p>The follow short set of rules are part of my overall ‘guidelines’ inspired by and adapted from <a href="http://www.twitter.com/csswizardry">@CSSWizardry</a> and <a href="http://www.twitter.com/necolas">@necolas</a> amonst many others.</p>
<ul>
<li>Use tabs (4) over spaces.</li>
<li>Never go more than 3 levels deep.</li>
<li>Write the CSS in alphabetical order (for quick duplication checking).</li>
<li>Always a space after the properies colon.</li>
</ul>
<h3 id="the-beginning-comment" tabindex="-1">The Beginning Comment</h3>
<p>Each ‘lump’ of Sass should have a comment explaining what it is doing, what it is for and an example of the HTML that it’s being applied to. These are the only CSS comments to be found in any Sass document. This is so you can have a multi-line comment without needing to include the // every line.</p>
<p>/*</p>
<p>Header Element
============</p>
<p>This is the Sass for the header element layout for the project.</p>
<p><header role=”banner”></p>
<p></header>
*/</p>
<h3 id="starting-your-sass" tabindex="-1">Starting your Sass</h3>
<p>At the top of your block of Sass you should include any $variables, @mixins and @extends that are relevant to the element.</p>
<p>.module {
$main-color: #D13400;</p>
<p>@include remit(margin-bottom, 24);</p>
<p>@extend %btn;</p>
<p>}</p>
<p>As you can see each Sass specific item has an empty line underneath. There is also an empty line at the end of the block too.</p>
<h3 id="add-all-the-things" tabindex="-1">Add all the things</h3>
<p>After you’ve declared these bits of Sass you would then include any CSS that the element requires.</p>
<p>.module {
$main-color: #D13400;</p>
<p>@include remit(margin-bottom, 24);</p>
<p>@extend %btn;</p>
<p>background-color: $main-color:
border-radius: $radius-sml;
cursor: pointer;
padding: 0 3%;
width: 24%;</p>
<p>}</p>
<h3 id="pseudo-%26-combinator-selectors" tabindex="-1">Pseudo &amp; Combinator Selectors</h3>
<p>If the element we’re coding up has a pseudo selector or there is a combinator selector required these go after the block of CSS we’ve added.</p>
<p>.module {
$main-color: #D13400;</p>
<p>@include remit(margin-bottom, 24);</p>
<p>@extend %btn;</p>
<p>background-color: $main-color:
border-radius: $radius-sml;
cursor: pointer;
padding: 0 3%;
width: 24%;</p>
<p>&amp;:hover, &amp;:focus {
background-color: darken($main-color, 30%);
}</p>
<p>&amp; &gt; li {
font-weight: 700;
}</p>
<p>}</p>
<h3 id="nesting-elements" tabindex="-1">Nesting Elements</h3>
<p>If you need to nest elements (no more than 3 levels deep). Then you would add the nested elements at the end of the block with a space between each nesting.</p>
<p>.element {
background: blue;
display: block;
margin: 0 auto;
width: 44.15467%;</p>
<p>h1 {
color: green;
font-size: 32px;
font-size: 2rem;
}</p>
<p>.box {
width: 80%;
margin: 0 auto;
}</p>
<p>}</p>
<h3 id="nesting-media-queries" tabindex="-1">Nesting Media Queries</h3>
<p>All media queries are nested inline with the element rather than ‘at the end’.</p>
<p>.element {  background: red;
@media (min-width: 700px) {
background: blue;</p>
<p>}</p>
<p>}</p>
<h3 id="nesting-media-queries-with-nested-elements" tabindex="-1">Nesting Media Queries with Nested Elements</h3>
<p>Media Queries are placed at the end of the block after the pseudo and combinator selectors and any other nested elements. With a space separating them.</p>
<p>.element {
background: blue;
display: block;
margin: 0 auto;
width: 44.15467%;</p>
<p>h1 {
color: green;
font-size: 32px;
font-size: 2rem;
}</p>
<p>.box {
margin: 0 auto;
width: 80%;
}</p>
<p>@media (min-width: 700px) {
width: 100%;</p>
<p>h1 {
font-size: 48px;
font-size: 3rem;
}</p>
<p>.box {
width: 95%;</p>
<p>&amp; &gt; li {
margin-left: 2%;</p>
<p>}
}</p>
<p>}</p>
<p>}</p>
<h3 id="inline-commenting" tabindex="-1">Inline Commenting</h3>
<p>If you need to add a comment to part of a block of Sass then you would add a Sass comment (not a CSS comment) after the element.</p>
<p>.box {
margin-bottom: (2 * $doc-line-height); // bigs more space</p>
<p>}</p>
<h3 id="wrapping-up." tabindex="-1">Wrapping Up.</h3>
<p>This is how I structure my Sass at the moment. It’s an on going process of legibility and ease of use. As I’m generally the only person that will write the Sass/CSS for a project this works for me. I beseech you to take this and rip it apart, move bits, add bits and role your own and document it for you and/or your team.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Sass-y box-sizing fallback if needs must</title>
      <link href="https://www.alwaystwisted.com/articles/a-sass-y-box-sizing-fallback-if-needs-must.html"/>
      <updated>2013-12-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-sass-y-box-sizing-fallback-if-needs-must.html</id>
      <content type="html">
        <![CDATA[
        <p>I’ve recently had to create a dozen or so HTML templates for a client who’s sites audience has are keen fans of Internet Explorer 7 and use it regularly using the site.</p>
<p>With my irking toward modern front-end development and leaving the past to have a working, accessible site that might not look the same but all the content would still be there. Unfortunately on this occasion I couldn’t just give IE7 a linear single column of the site using something like Universal-IE7.</p>
<p>My main issue with the layout of the pages for this project is I’ve been using <code>box-sizing: border-box;</code> since last <a href="https://twitter.com/StuRobson/statuses/162674112991477761?tw_i=162674112991477761&amp;tw_e=details&amp;tw_p=archive">year</a>. Internet Explorer 7 and some (very old gecko and webkit browsers) don’t support this fantastic bit of CSS.</p>
<p>So I took to Codepen (it’s pretty much my first port of call for any HTML/CSS/JS thing I do) and started fleshing out a nice simple Sass mixin to create the compiled CSS for IE8 and up and then a different set of compiled CSS for IE7 and below.</p>
<h3 id="the-results" tabindex="-1">The Results</h3>
<p>I created a small little mixin that would allow you define a left and/or right padding as well as the width of the element. It would compile and create the width and padding for modern browsers and then create a set of CSS for IE7 at the same time adding a conditional comment. Currently you can set the widths in px or with percentages. I am trying to work out how to include ems for padding with a percentage width but haven’t got around to it yet. I just wanted to get this out there.</p>
<h3 id="so-where-is-it%3F" tabindex="-1">So where is it?</h3>
<p>It’s built in to my recently updated set of Sass mixins and files - <a href="https://github.com/sturobson/Sassifaction">Sassifaction</a>.</p>
<p>Therein it’s also built and ready in my Mixture Project - <a href="https://github.com/sturobson/Sassifaction-Mixture">Sassifaction Mixture</a>.</p>
<p>If you just want it on it’s own or have a play it’s also on <a href="http://codepen.io/sturobson/pen/uitIq">CodePen</a>.</p>
<h3 id="update%3A" tabindex="-1">Update:</h3>
<p>Thanks to the impecably dressed <a href="http://scottrileydesigns.co.uk/">Scott Riley</a> and a quick <a href="http://codepen.io/anon/pen/fraze">codepen</a> <a href="http://codepen.io/sturobson/pen/uGtEa">shuffle</a>, it's been updated and made a little cleaner</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Web Performance, the tools I use</title>
      <link href="https://www.alwaystwisted.com/articles/web-performance-the-tools-i-use.html"/>
      <updated>2013-12-19T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/web-performance-the-tools-i-use.html</id>
      <content type="html">
        <![CDATA[
        <p>Over the last 48 hours or so I've been asked a number of times about the tools I use when testing a sites performance. I thought it'd be frugal to have a link to point people at with a little explanation rather than a bombardment of 140 characters.</p>
<h3 id="web-page-test" tabindex="-1"><a href="http://www.webpagetest.org">Web Page Test</a></h3>
<p>This is the tool I often go to first. It allows you to enter an URL, decided where you want to test in the world and in what browser. This then tests the site (upto 9 times) and gives you several results to glean information from including a traffic light system of what you’re doing right, ok at or completely wrong.</p>
<h3 id="gtmetrix" tabindex="-1"><a href="http://gtmetrix.com/">GTMetrix</a></h3>
<p>This site combines two great tools into one nice package. Adding your URL runs the test through both Google’s PageSpeed and Yahoo’s YSlow resulting in a percentage score for both with pointers as to what needs doing in underneath. This is the tool I often tweet a screengrab from.</p>
<h3 id="mobitest" tabindex="-1"><a href="http://mobitest.akamai.com">Mobitest</a></h3>
<p>This is a great tool that just allows you to test a sites performance on a mobile device which is a great way to see how much data is being pushed to that pocket computer you've got in your hand.</p>
<p>These tools give you results in what you can do better most of which I’ve mentioned in <a href="../post.php%EF%B9%96s=2013-11-23-quick-wins-in-web-performance.html">a previous post</a>.</p>
<h3 id="recommended-reading" tabindex="-1">Recommended Reading</h3>
<p>If you’re really interested in web performance as a developer (and you really should be) then here’s a couple of books I’d highly recommend.</p>
<p>Web Performance by <a href="http://twitter.com/AndyDavies">Andy Davies</a> Available now as <a href="http://www.fivesimplesteps.com/products/web-performance">an eBook from Five Simple Steps</a></p>
<p>High Performance Browser Networking by <a href="http://twitter.com/igrigorik">Ilya Grigorik</a> Available freely <a href="http://chimera.labs.oreilly.com/books/1230000000545">online</a>, as an <a href="http://shop.oreilly.com/product/0636920028048.do">eBook</a> or a <a href="http://www.amazon.co.uk/High-Performance-Browser-Networking-performance/dp/1449344763">paperback</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Using Mixture for client review</title>
      <link href="https://www.alwaystwisted.com/articles/using-mixture-for-client-review.html"/>
      <updated>2013-12-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/using-mixture-for-client-review.html</id>
      <content type="html">
        <![CDATA[
        <p>Most of the time I’m coding up ‘flat’ HTML for clients to then crack open and add to their CMS.</p>
<p>I’ve been using <a href="http://www.mixture.io">Mixture</a> for quite a time now (just over a year, where’s that time gone?) and I find the ability to host the work I’m doing on their servers as part of their monthly package fantastic.</p>
<p>Doing this means the client can see where I'm up to at anytime I push an update and also easily check it on their mobile or tablet device (or any device).</p>
<p>It’s also really good that it allows you to password protect the project if you wish to. Which is great for clients as there’s no chance someone else can happen upon the site and see what’s occurring, keeping any NDA intact.</p>
<p>I’d thought I’d share with you how I do this.</p>
<p>To make it easy for clients to remember the URL for their project to review I simply setup a redirect from my domain.</p>
<p>This way the client could (hopefully) easily remember myCompany.alwaystwisted.com rather than myCompany.alwaystwisted.mixture.io</p>
<p>A pretty simple ‘trick’ and a breeze to quickly set-up.</p>
<p>Of course, you could do this by just uploading the site to your server via FTP each time, but w/ Mixture it's one click and it's doing all that for you. Speedy.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sass: An introduction. A workshop at Port80</title>
      <link href="https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-at-port80.html"/>
      <updated>2013-12-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-at-port80.html</id>
      <content type="html">
        <![CDATA[
        <p>I think <a href="http://port80events.co.uk/">Port80</a> was the first conference I went to where I thought. “I should be working in this industry full-time” rather than the night-owl work I was doing at the time.</p>
<p>Jump forward a short 19 months or so and I’m really happy to announce that at Port80 this next year (2014) I’m hosting a half-day workshop on an introduction to Sass.</p>
<p>One May 15th I’ll be presenting a workshop on Sass.</p>
<p>It’d be great to <a href="http://port80events.co.uk/event/port80-2014/">see you there</a>.</p>
<p>Get your tickets now from this <a href="http://port80events.co.uk/port80-workshops-in-may/">handy little link</a>.</p>
<h2 id="what-will-you-learn%3F" tabindex="-1">What will you learn?</h2>
<p>First we’ll look at CSS pre-processors, why and where you would use them, what they do and how they work. After this we’ll move onto how to use the power of Sass to make your CSS authoring more efficient and hopefully more fun.</p>
<h3 id="things-that-will-be-covered" tabindex="-1">Things that will be covered</h3>
<ul>
<li>Options for installing Sass on your machine</li>
<li>The two syntaxes, Sass &amp; SCSS</li>
<li>Variables, mixins and includes</li>
<li>Extends and placeholders</li>
<li>Built in functions</li>
<li>Media queries &amp; nesting</li>
<li>Compass, Bourbon and other frameworks</li>
<li>Sass and front-end performance</li>
<li>And more!</li>
</ul>
<h3 id="about-me" tabindex="-1">About me</h3>
<p>Stu Robson is a front-end developer from the deepest parts of Wiltshire, having been a night-owl freelancer for two years he took the jump into working full-time in January 2013. If he’s not coding he’s tweeting. If he’s not tweeting he’s usually spending time with his partner, Sarah and son, Ethan.</p>
<h3 id="additional-information" tabindex="-1">Additional information</h3>
<p>Please bring your laptop (hopefully with Sass installed) as this will in part be a practical workshop. Going through building a new project homepage using Sass.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sass: An introduction. A workshop in Cardiff</title>
      <link href="https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-in-cardiff.html"/>
      <updated>2013-12-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sass-an-introduction-a-workshop-in-cardiff.html</id>
      <content type="html">
        <![CDATA[
        <p>I love what <a href="http://www.twitter.com/craiginwales">Craig</a> and <a href="http://twitter.com/amieduggan">Amie</a> have managed to achieve in such a short space of time. Spending an afternoon at <a href="http://foundershub.co.uk/">Founders Hub</a> I could see the passion and effort litterally beaming from every room.</p>
<p>It’s great that they’ve created something that in part gives something back to the community by just being there as an option for your office.</p>
<p>I’m a great believer in giving something back. I find this industry fantastic because of how happily everyone is in sharing what they learn more often than not for free.</p>
<p>Again, I digress. A few days after <a href="https://www.alwaystwisted.com/articles/handheldconf.com">Handheld Conference</a>, where the day before I attended a workshop at the Founders Hub Craig tweeted asking if there’s any interest in more workshops held at the venue. I quickly threw my cards on the table offering a half-day workshop to whoever wishes to attend (hopefully people interested in the subject).</p>
<p>So here we have it.</p>
<p>On January 8th at just gone noon I’ll be presenting a workshop on Sass.</p>
<p>If you're interested in attending I suggest you pop on over to <a href="http://foundershub.co.uk/calendar/intro-to-sass?view=calendar">this page at the Founders Hub website</a>.</p>
<p>update: all places for this have now been snapped up, which for me is kinda amazing. Looking forward to seeing you there.</p>
<h3 id="so-what's-being-discussed-in-this-workshop%3F" tabindex="-1">So what's being discussed in this workshop?</h3>
<p>A half-day workshop guiding you through the productivity-improving aspects of using the CSS pre-processor, Sass.</p>
<h2 id="what-will-you-learn%3F" tabindex="-1">What will you learn?</h2>
<p>First we’ll look at CSS pre-processors, why and where you would use them, what they do and how they work. After this we’ll move onto how to use the power of Sass to make your CSS authoring more efficient and hopefully more fun.</p>
<h3 id="things-that-will-be-covered" tabindex="-1">Things that will be covered</h3>
<ul>
<li>Options for installing Sass on your machine</li>
<li>The two syntaxes, Sass &amp; SCSS</li>
<li>Variables, mixins and includes</li>
<li>Extends and placeholders</li>
<li>Built in functions</li>
<li>Media queries &amp; nesting</li>
<li>Compass, Bourbon and other frameworks</li>
<li>Sass and front-end performance</li>
<li>And more!</li>
</ul>
<h3 id="about-me" tabindex="-1">About me</h3>
<p>Stu Robson is a front-end developer from the deepest parts of Wiltshire, having been a night-owl freelancer for two years he took the jump into working full-time in January 2013. If he’s not coding he’s tweeting. If he’s not tweeting he’s usually spending time with his partner, Sarah and son, Ethan.</p>
<h3 id="additional-information" tabindex="-1">Additional information</h3>
<p>This is more of a show and tell rather than a practical workshops. But please do bring your favourite laptop with you.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>What&#39;s in my bookmarks bar</title>
      <link href="https://www.alwaystwisted.com/articles/whats-in-my-bookmarks-bar.html"/>
      <updated>2013-11-25T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/whats-in-my-bookmarks-bar.html</id>
      <content type="html">
        <![CDATA[
        <p>I decided to spend some time this evening tidying up my bookmarks in Chrome.</p>
<p>Along with clearing out what I've bookmarked over the years I thought I'd tidy up my bookmarks bar as well.</p>
<p><img src="https://www.alwaystwisted.com/blog/bookmarks.png" alt="image of bookmarks bar" loading="lazy" decoding="async"></p>
<p>I save my bookmarks bar for predominantly handy JS bokmarklets. After tidying these up I thought it'd be something good to share.</p>
<p>So here goes...</p>
<p><a href="http://www.josscrowcroft.com/2011/code/window-size-bookmarklet/">Window Size Bookmarklet<br>
</a>A simple bookmarklet that gives a pixel value for the width and height of the browser viewport. As I convert px to em with Sass I find this easy and quick to understand</p>
<p><a href="https://gist.github.com/sturobson/6639967">New 'iPhone' Window<br>
</a>This opens what ever page you're on into a new window with reduced browser chrome to a size relative to an iPhone. This is good when using with Crhomes Dev Tools but I don't open it often anymore.</p>
<p><a href="https://gist.github.com/tzi/1607453">Print Preview<br>
</a>Without wasting paper until you really have to, here's a quick way to show how the page would look if printed.</p>
<p><a href="http://davatron5000.github.io/deCSS3/">deCSS3<br>
</a>From <a href="http://www.twitter.com/davatron5000">Dave Rupert</a>, this strips out any and all CSS3 so that you can have a quick look to make a guess at what older browsers would potentally render the page like.</p>
<p><a href="http://squizlabs.github.io/HTML_CodeSniffer/">HTML_codesniifer<br>
</a>A nice accessibility checker giving you a traffic light system of what's not right and how to fix it.</p>
<p><a href="http://www.benjaminkeen.com/open-source-projects/smaller-projects/responsive-design-bookmarklet/">RWD multiple pages<br>
</a>A bookmarklet that loads the current site into several mobile/tablet sizes iframes for quick checking. I don't open this one often.</p>
<p><a href="http://diagnosticss.github.io/">Diagnostic.css<br>
</a>This gives a visual indication of where your site would be inaccessible and where you have invalid markup.</p>
<p><a href="http://lab.maltewassermann.com/viewport-resizer/">Resizer<br>
</a>This gives you a little menu to makes the page your on resize to various preset viewport widths</p>
<p><a href="http://seesparkbox.com/foundry/media_query_bookmarklet">Media Query Bookmarklet<br>
</a>From the fine people of <a href="http://www.seesparkbox.com">Sparkbox</a> this gives you a ruler, it also outputs where your cursor is in X/Y but the beauty is that it shows you all the media queries being called at whatever size the browser is set at.</p>
<p>I've also got a bookmarklet for <a href="http://www.sassmeister.com">Sassmeister</a> and to create a new pen on <a href="http://www.codepen.io">CodePen</a> and that's it. Some handy little bookmarklets helping me make, test, break and fix websites every day.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sass and Base64 images</title>
      <link href="https://www.alwaystwisted.com/articles/sass-and-base64-images.html"/>
      <updated>2013-11-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sass-and-base64-images.html</id>
      <content type="html">
        <![CDATA[
        <p>Recently I was working on a client site with various triangular carat icons denoting if something was open or closed or whether it was a link. As the images were so small and after optimising them even small i thought I’d encode them in the CSS.</p>
<p>This got me thinking about how to use them with Sass.</p>
<p>Although I use Sass I still like a ‘tidy’ stylesheet before compiling. Adding Base64 encoded images gives me a chunk of text I don’t like the look of in my code. So it got me thinking.</p>
<h2 id="partials" tabindex="-1">Partials</h2>
<p>I had a cunning plan. Using a partial (_base64.scss) I thought I could add all my base64 images in there then, using a %placeholder for each one, I could @extend them in to my other stylesheet(s) where needed.</p>
<p>This worked perfectly. In my _base64.scss file I’ve got something similar to this -</p>
<p>%carat-triangle--up {
background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAALCAYAAACzkJeoAAAAVklEQVQY02N4+uzNVCBmY8AGgBL/gfg4EEvjkgThl0DsiEsShH8DcSkQM2KThOE1QMyHSxKEN+GSXI9N5x8grsRm5ysgdsbm2pNALIfNn9OBmB1bAAEAjTeww9HNXe8AAAAASUVORK5CYII=);
}</p>
<p>To which I then included it into something like this -</p>
<p>.error-message {
// code for error message
&amp;:before {
@extend %carat-triangle--up
// code for included this icon
}
}</p>
<p>Using %placeholder and @extend means I can call the the icon what it is, clearly and concisely. Where as in the compiled CSS file it might be part of the .error-message I would easily be able to tell from the @extend that what it looks like, a %carat-triangle--up.</p>
<p>Now I’ve got some nice icons in the stylesheet saving on HTTP requests but I don’t see them as they’re (to me) hidden away when working on my Sass files.</p>
<h2 id="compass" tabindex="-1">Compass</h2>
<p>If you’re using <a href="http://compass-style.org/">Compass</a>, you can forgo having to create the Base64 images by letting the framework <a href="http://compass-style.org/reference/compass/helpers/inline-data/#inline-image">do the work for you</a>. Including the image you want to be a data-uri like this -</p>
<p>background-image:  inline-image(‘carat-open.png’);</p>
<p>When compiled will create the Base64 code for you. So you might not even need a separate partial.</p>
<h2 id="mixture" tabindex="-1">Mixture</h2>
<p>The guys at <a href="http://mixture.io/">Mixture</a> are awesome. I mentioned this feature to them a while ago and within 48 hours it was <a href="http://docs.mixture.io/preprocessors#base">in the app</a>. So if you use Sass, LESS or Stylus you can do the same thing using this code -</p>
<p>background-image: inline-image('carat-open.png');</p>
<p>Will also output the Base64 code when Mixture compiles.</p>
<h2 id="base64-encoded-files" tabindex="-1">Base64 encoded files</h2>
<p>If you’re supporting modern browsers (IE8+) then you’d be easily able to include Base64 images into your compiled CSS file. Note that Base64 encoding adds about 25-30% to the file size of the original image file size so don’t use it for everything. Personally, I never encode anything that’s larger than 4kb as an image.</p>
<h2 id="performance" tabindex="-1">Performance</h2>
<p>They’re have been <a href="http://www.mobify.com/blog/data-uris-are-slow-on-mobile/">several</a> <a href="http://www.mobify.com/blog/base64-does-not-impact-data-uri-performance/">recent</a> <a href="http://java-performance.info/base64-encoding-and-decoding-performance/">posts</a> about the performance of using Base64 encoded files over using actual images. There is no silver bullet. The best thing to do is test both early and see which will be the best way to go.</p>
<p>This helps me, a tidy set of Sass partials is a tidy mind, hiding the ‘random’ collection of letters and numbers or even the files I’m importing just helps me build my projects out.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>quick wins in web performance</title>
      <link href="https://www.alwaystwisted.com/articles/quick-wins-in-web-performance.html"/>
      <updated>2013-11-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/quick-wins-in-web-performance.html</id>
      <content type="html">
        <![CDATA[
        <p>Following on from a workshop by <a href="https://twitter.com/andydavies">Andy Davies</a> I attended at <a href="http://port80events.co.uk/">Port80</a> this year I am forever looking at how newly launched sites perform. Most of them, invariably, have things that could do with tightening up, making the overall file size smaller and making them download and run quicker.</p>
<p>Running your site through something like <a href="http://www.webpagetest.org">webpagetest.org</a> or <a href="http://www.gtmetrix.com">gtmetrix.com</a> will help show you (through their summary pages) where you could improve your sites performance by pointing out where it’s currently failing.</p>
<p>Below are some ‘quick wins’. Some easy things to do to make your sites better, smaller and more performant.</p>
<h2 id="image-optimisation" tabindex="-1">Image Optimisation</h2>
<p>Optimising images is something that’s quite easy to do but it’s also something that’s often missed. They’re also, more generally, the biggest part of a web page in terms of file size. There are a couple of ways that we can help reduce a web pages file size and performance by doing some simple things.</p>
<p>Are you using the correct file format? It’s easy to export a photo as a PNG24 in Photoshop but wouldn’t it be better as a jpg? Would it be better to use an SVG instead of some gifs for your social media icons. Thinking about what the file type is you’re actually needing will help reduce the file size before you’ve left Photoshop.</p>
<p>Once you’ve got the correct file format are they as optimised as possible. You can only do so much with Firework or Photoshop. You’ll need to use a compression tool like <a href="http://imageoptim.com/">imageoptim</a>(lossless compression), <a href="https://www.alwaystwisted.com/articles/jpegmini.com">jpegmini</a>(lossy compression), <a href="https://github.com/svg/svgo">SVGO</a>(for compressing SVG files) or something integrated in an application that’ll squeeze the kilobytes out of the files even more again reducing the over file size of the page.</p>
<p>If there are several icons on the site you’re building. Rather than give each one a separate file which you would call in the CSS (for example) create a sprite sheet. Making only one file of several files helps reduce the calls to the server for the image required.</p>
<h2 id="removing-duplication-and-cruft" tabindex="-1">Removing Duplication and Cruft</h2>
<p>As mentioned in a <a href="../post.php%EF%B9%96s=2013-11-11-case-study-the-up-group-website-performance.html">previous blogpost</a> I wrote how I made a quick win by spotting duplicate code for Google analytics. Going through your site and removing any duplication you find will be a very quick win.</p>
<p>As well as duplicate code, there may be code that started out being used in the project but is now redundant. Removing any of this redundant code (with something like <a href="https://github.com/giakki/uncss">UnCSS</a>) will help reduce your file size.</p>
<h2 id="bad-requests" tabindex="-1">Bad Requests</h2>
<p>We’re all human, sometimes we mistype things, sometimes we forget to delete references to things we’ve deleted. Looking at what gets downloaded by your browser will tell you if, somewhere in the page, you’re referencing something that doen’t exist.</p>
<p>Browsers are triers. If it fails to find something you’ve included, an image or font file for example, it will continue to look for it just in case it itself failed on the first time to grab it from the server. If this was a font then your sites visitor could be faced with a page with no text for some time. Checking this whilst in development and before you push live will help stop this happening.</p>
<h2 id="putting-your-javascript-at-the-end-of-the-document" tabindex="-1">Putting your JavaScript at the end of the document</h2>
<p>Putting as much JavaScript at the bottom of the page defers the loading of that JS. JavaScript at the top of the document in the</p>
<p>will block the page rendering giving the sites visitor a blank page until it’s finished loading. Putting it at the bottom will help this as the page will render the HTML and CSS without being blocked.</p>
<h2 id="reducing-http-requests" tabindex="-1">Reducing HTTP requests</h2>
<h3 id="css" tabindex="-1">CSS</h3>
<p>You don’t need a separate file for your reset. Your print stylesheet is so small you can add it the end. You really only need to send one CSS file down the pipe.</p>
<p>Now with responsive web design you might have a mobile, tablet and desktop CSS file. You really don’t need to split them up. One file to rule them all. Cuts down the amount of HTTP requests meaning your page might actually perform a little bit better.</p>
<p>For this a pre-processor really helps. You can easily import all of your Sass/LESS/Stylus files into one so when it compiles you get one gorgeous CSS file. That way you can still have the separate ‘bits’ of CSS to code but have one file on the server. Doing this with just CSS you just have one file and write all of your CSS in that one file.</p>
<h3 id="js" tabindex="-1">JS</h3>
<p>You could do the same for your JS. I don’t I like to keep certain bits in their own file. If I use jQuery it gets its own file with its own HTTP request as do <a href="https://www.alwaystwisted.com/articles/modernizr.com">Modernizr</a> and Google Analytics.</p>
<p>Where I do concatenate and conjoin files is to keep any ‘plugin’ Javascript in one file ‘plugins.js’ and one for any other code ‘scripts.js’. So if you’ve got a plugin for a mobile menu, a slider, a back-to-top button. Rather than 3 files that would all go into the plugins.js file.</p>
<h2 id="minification" tabindex="-1">Minification</h2>
<h3 id="html" tabindex="-1">HTML</h3>
<p>If you wanted to you could minify the HTML of your webpages. To be honest I’ve never done this. I’m sure if you quickly google you’ll be able to find something that’d do this but when you bring in the various CMSs available today for me it’s just easier to leave it as it is. Remove your comments though doesn’t need to be there in your production code.</p>
<h3 id="css-1" tabindex="-1">CSS</h3>
<p>When you’re writing CSS I’m sure, like me, you want to be able to quickly understand what each bits doing, adding comments so you can easily scan and find the relevant CSS you need to edit.</p>
<p>The browser doesn’t care about readability. It doesn’t matter how you’ve nicely laid out your CSS and what comments you’ve added. A quick win here would be to minify the CSS you’ve concatenated so that it strips out and whitespace and any comments you’ve added. This will shave down the kilobytes being pulled down the pipe meaning a faster download.</p>
<p>If you use a pre-processor then you can easily add all the comments you want in the world and then minify the outputted CSS when compiling. There are several apps that allow you to do this for LESS, Stylus and Sass. If you’re still writing CSS without one of these you can still minify the CSS from various applications.</p>
<h3 id="javascript" tabindex="-1">JavaScript</h3>
<p>Minifying your JavaScript is something to do for the same reasons as previously mentioned. The browser won’t care and it’ll save you a little overall file size.</p>
<h2 id="gzip" tabindex="-1">Gzip</h2>
<p>Gzip’ing takes your minified CSS and JavaScript and squeezes even more from it. Squeezing the file size again means a smaller overall page size meaning, potentially, a quicker download. For example, if you were to minify and then GZip jQuery you could reduce the size to around 22% of its original uncompressed file size.</p>
<p>To enable this you must be able to access the server as you’d need to edit (or create) the .htaccess file and add this code -</p>
<p>#Gzip
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript text/javascript
</ifmodule>
#End Gzip</p>
<h2 id="adding-expires" tabindex="-1">Adding Expires</h2>
<p>Chances are when the site goes live it’s CSS file won’t change that often. The Javascript file, logo and social media icons also might not change until the next redesign/realign. Adding expires or a cache-control header to the .htaccess file can stop the browser from downloading files unless it needs to. Caching what you tell it so the next time the visitor comes to the site, hopefully, they’ll get the page faster than the first time.</p>
<p>You could add this (taken from the <a href="https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess">HTML5 Boilerplate</a>)</p>
<p><IfModule mod_expires.c>
ExpiresActive on</p>
<p># Perhaps better to whitelist expires rules? Perhaps.
ExpiresDefault                          'access plus 1 month'</p>
<p># cache.appcache needs re-requests in FF 3.6 (thx Remy ~Introducing HTML5)
ExpiresByType text/cache-manifest       'access plus 0 seconds'</p>
<p># Your document html
ExpiresByType text/html                 'access plus 0 seconds'</p>
<p># Data
ExpiresByType text/xml                  'access plus 0 seconds'
ExpiresByType application/xml           'access plus 0 seconds'
ExpiresByType application/json          'access plus 0 seconds'</p>
<p># RSS feed
ExpiresByType application/rss+xml       'access plus 1 hour'</p>
<p># Favicon (cannot be renamed)
ExpiresByType image/x-icon              'access plus 1 week'</p>
<p># Media: images, video, audio
ExpiresByType image/gif                 'access plus 1 month'
ExpiresByType image/png                 'access plus 1 month'
ExpiresByType image/jpg                 'access plus 1 month'
ExpiresByType image/jpeg                'access plus 1 month'
ExpiresByType video/ogg                 'access plus 1 month'
ExpiresByType audio/ogg                 'access plus 1 month'
ExpiresByType video/mp4                 'access plus 1 month'
ExpiresByType video/webm                'access plus 1 month'</p>
<p># HTC files  (css3pie)
ExpiresByType text/x-component          'access plus 1 month'</p>
<p># Webfonts
ExpiresByType font/truetype             'access plus 1 month'
ExpiresByType font/opentype             'access plus 1 month'
ExpiresByType application/x-font-woff   'access plus 1 month'
ExpiresByType image/svg+xml             'access plus 1 month'
ExpiresByType application/vnd.ms-fontobject 'access plus 1 month'</p>
<p># CSS and JavaScript
ExpiresByType text/css                  'access plus 1 year'
ExpiresByType application/javascript    'access plus 1 year'
ExpiresByType text/javascript           'access plus 1 year'</p>
<p><IfModule mod_headers.c>
Header append Cache-Control 'public'
</IfModule></p>
<p></IfModule></p>
<p>The browser will cache and keep the files for as long as specified, if possible. I say if possible because every browser has a different amount of ‘space’ for caching. On a mobile browser it’s even less so. Doing this helps to possibly speed up future visits and that’s worth doing I reckon.</p>
<h2 id="applications" tabindex="-1">Applications</h2>
<h3 id="less%2C-sass%2C-stylus" tabindex="-1">LESS, Sass, Stylus</h3>
<ul>
<li><a href="https://www.alwaystwisted.com/articles/mixture.io">Mixture</a> (OSX/Win)</li>
<li><a href="https://www.alwaystwisted.com/articles/incident57.com/codekit">Codekit</a> (OSX)</li>
<li><a href="http://alphapixels.com/prepros/">Prepos</a> (OSX/Win)</li>
</ul>
<h3 id="less" tabindex="-1">LESS</h3>
<ul>
<li><a href="http://incident57.com/less/">LESS.app</a> (OSX)- hasn’t been updated since March 2013</li>
</ul>
<h3 id="sass" tabindex="-1">Sass</h3>
<ul>
<li><a href="http://mhs.github.io/scout-app/">Scout</a> (OSX/Win)</li>
<li><a href="http://compass.kkbox.com/">Compass.app</a> (OSX/Win)</li>
<li>Command Line</li>
</ul>
<h3 id="other" tabindex="-1">Other</h3>
<ul>
<li><a href="http://procssor.com/">Procssor</a> (OSX)</li>
</ul>
<h3 id="web-based" tabindex="-1">Web-based</h3>
<ul>
<li><a href="http://procssor.com/">Procssor</a></li>
<li><a href="http://www.jsmini.com">jsmini.com</a></li>
<li><a href="http://marijnhaverbeke.nl/uglifyjs">uglify</a></li>
</ul>
<h2 id="recap" tabindex="-1">Recap</h2>
<p>Hopefully this has helped put fire in your belly. Making your site as lean as possible is not only good for your visitors, it's also good for your server costs. Smaller file sizes and less file means less storage space required and less bandwidth needed for the site to be accessed.</p>
<p>Everyone's a winner baby, that's the truth</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Case Study: The Up Group Website Performance</title>
      <link href="https://www.alwaystwisted.com/articles/case-study-the-up-group-website-performance.html"/>
      <updated>2013-11-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/case-study-the-up-group-website-performance.html</id>
      <content type="html">
        <![CDATA[
        <p>I was recently contacted by Manne from The Up Group. He wanted me to take a look at their site (built on ModX) to see what was making the site (and it’s homepage predominantly) load slowly and what could be done to improve the performance of their website <a href="http://www.theupgroup.com">www.theupgroup.com</a>.</p>
<h2 id="preliminary-review" tabindex="-1">Preliminary Review</h2>
<p>Before moving straight into the codebase to see what I could glean from it I ran several tests to using some web page performance applications.</p>
<p>The tools I used were Google’s PageSpeed Chrome <a href="https://developers.google.com/speed/pagespeed/">DevTools extension</a>, a test on <a href="https://www.alwaystwisted.com/articles/webpagetest.org">WebPageTest</a> and a test on <a href="http://gtmetrix.com/">GTMetrix</a>.</p>
<p>The initial resulting score from GTMetrix was -</p>
<p><img src="https://www.alwaystwisted.com/blog/UpGroupBEFORE.gif" alt="UpGroup Performance Statistics Before" loading="lazy" decoding="async"></p>
<p>On average it took the sites homepage 4.3 seconds to download and have a time to first byte at a very slow average of 2.4 seconds so was lots of room for improvement.</p>
<p>In the review I noted that to improve the pages download speed and time there was oppurtunity to reduce HTTP requests, make the CSS and JavaScript filesizes smaller, removing anything that’s no longer needed and optimising the images used.</p>
<h2 id="asset-location-and-http-requests" tabindex="-1">Asset location and HTTP requests</h2>
<p>Looking at the HTML the JavaScript was being called at the top of the page. This was blocking the rest of the page from being loaded (the HTML at minimum) whilst the JavaScript had downloaded and run.</p>
<p>There were also 5 separate JavaScript files being called as well as 3 different CSS files being called on the page. Concatenating these into fewer HTTP requests would mean the site isn’t having to connect to the server more times than it needs to to load the page.</p>
<h2 id="duplication-of-file-requests" tabindex="-1">Duplication of file requests</h2>
<p>Going through the page I noticed there were two calls to the favicon.ico and also two calls to the Google Analytics code. Removing these reduced two unneeded HTTP request. A nice and simple quick win.</p>
<h2 id="minify-%26-gzip" tabindex="-1">Minify &amp; GZip</h2>
<p>With the JavaScript and CSS now taking fewer HTTP request to get to the browser it was time to look out squashing every byte out to make them as small as possible.</p>
<p>To that end minifying both the CSS and JS files gave a saving of around 80kb on the total page weight.</p>
<p>I also edited the .htaccess file to GZip the JavaScript and CSS files to reduce the file sizes a little bit more too.</p>
<h2 id="image-optimisation" tabindex="-1">Image Optimisation</h2>
<p>The site has a logo and two social icons in the header, on the homepage there is a black and white image of a man hold the company ident as well as 20 logos from companies that The Up Group has worked with. I used <a href="http://imageoptim.com/">ImageOptim</a> to squeeze the file size of the site logo, icons and ‘man’ as well as the group of logos used.</p>
<p>For the logos I also put them into one image sprite sheet and used CSS to save 19 separate HTTP requests for the page.</p>
<h2 id="caching" tabindex="-1">Caching</h2>
<p>Once all these were done I went back to the .htaccess file to extend the caching period of the files so that the browser would keep them in the hope the next time the visitor goes to the site they wouldn’t have to download everything all over again.</p>
<h2 id="improvements" tabindex="-1">Improvements</h2>
<p>In doing all these things above I then ran the site through the tests above again and found that there was a significant improvement. Both the download time and the time to first byte were improved as were the scores -</p>
<p><img src="https://www.alwaystwisted.com/blog/UpGroupBEFORE-AFTER.gif" alt="UpGroup Site Performance After" loading="lazy" decoding="async"></p>
<p>I don’t think that’s a bad effort for around a days work. I also gave the sites homepage a facelift, but I’ll keep that for another blogpost.</p>
<p><a href="http://www.theupgroup.com"><img src="https://www.alwaystwisted.com/blog/UpGroupHomePage.jpg" alt="UpGroup Redesign" loading="lazy" decoding="async"></a></p>
<p>(note: the site has had a complete redesign by others since I did this work. The results may vary differently if you tested now).</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Deciding in the Browsers</title>
      <link href="https://www.alwaystwisted.com/articles/deciding-in-the-browsers.html"/>
      <updated>2013-09-03T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/deciding-in-the-browsers.html</id>
      <content type="html">
        <![CDATA[
        <p>Just a thought. Now that some web designers and developers are moving to ‘designing in the browser’ are we unintentionally boxing ourselves by doing so? Are designers now mainly designing in one browser at different sizes.</p>
<p>I hope not. That does not really work.</p>
<h3 id="time-flies" tabindex="-1">Time Flies</h3>
<p>I really cannot believe it was 2008 when Andy Clarke proposed the idea of designing in the browser. I guess it’s because it’s being reiterated in many forms that it just seems like a fresh idea still.</p>
<p>Although there are many posts, talks, interviews about how we should all be designing in the browser there are no rules and if you cannot design purely in the browser that’s not a problem.</p>
<p>It’s not binary.</p>
<h3 id="%E2%80%9Cdeciding-in-the-browser%E2%80%9D" tabindex="-1">“Deciding in the browser”</h3>
<p>The phrase reimagined by Dan Mall in September 2012 shows the progression of thought around the idea. I think it needs changing. Ever so slightly. “Browser” to me just screams ‘one thing’. If we made this ‘browsers’ I’d be happier. This, to me, means more than resizing your chrome window.</p>
<h3 id="i-saw-a-site-today%2C-oh-boy." tabindex="-1">I saw a site today, Oh boy.</h3>
<p>So this is all spurred on from a recent designers new site being launched. If you know me, you’ll know I’m pretty much on twitter 24/7. Consequently I’d say 98% of all links I click are opened in Chrome iOS rather than Chrome on my Air.</p>
<p>So clicking a link I was presented with a readability nightmare. 3/4 words per line of text and huge amount of margin either side of the text. Without getting my Gridset ruler out I would guess at 80 pixels of my 320 pixels was made up of white space. 25% of a small screen is quite large.</p>
<p>Checking the site on my Air though, at 320 pixels wide, and it looked nice. The margin didn’t seem so huge. It worked.</p>
<p>This’d be where, possibly, deciding in just the one browser isn’t a great idea. You need to decide, design and test on anything you’ve got to hand to make the best device-agnostic site you can.</p>
<p>So, let’s call it ‘deciding in the browsers’ whether we start with Photoshop or HTML/CSS. Just don’t restrict yourself to one browser.</p>
<p>Okay?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Why not write a book?</title>
      <link href="https://www.alwaystwisted.com/articles/why-not-write-a-book.html"/>
      <updated>2013-08-25T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/why-not-write-a-book.html</id>
      <content type="html">
        <![CDATA[
        <p>Ok. So I'm thinking of writing a book.</p>
<blockquote>
<p>'Everybody does have a book in them, but in most cases that's where it should stay.'</p>
<p>Christopher Hitchens</p>
</blockquote>
<p>It's (at this moment) titled – 'Modern Front-End Development Using Sass'.</p>
<p>I'm hoping to take people through the processes of setting up and using Sass to create beutifully maintainable front-end code. It's not all about Sass though, it's also about developing your own boilerplate. Something I'm very passionate about. With the importance of having code that anyone can understand by creating your own 'guidelines' and also ways that your maintainable code should be as performant as possible.</p>
<p>The idea is in its gestation period at the moment. Who knows, bear with me.</p>
<p>Let's see how this goes. It might go a bit '<a href="http://www.urbandictionary.com/define.php?term=it's%20all%20gone%20pete%20tong">Pete Tong</a>' but hopefully not.</p>
<p>If you're interested in this, a comment would be greatly appreciated.</p>
<p>Thanks,</p>
<p>S</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Look Ma, I&#39;m on the telly!</title>
      <link href="https://www.alwaystwisted.com/articles/look-ma-im-on-the-telly.html"/>
      <updated>2013-08-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/look-ma-im-on-the-telly.html</id>
      <content type="html">
        <![CDATA[
        <p>Ok, so not totally true.</p>
<p>In July I was more than happy to talk to a bunch of like minded fellows at an event held the Mozilla space in London. The event was organised by my two good friend <a href="http://www.twitter.com/mrqwest">Anthony</a> and <a href="http://www.twitter.com/onishiweb">Adam</a> masterminds behind <a href="http://12devs.co.uk/">12Devs</a>. This was there third foray into evening mini-conferences after having two great years of collating articles for the 12 days following Christmas Day.</p>
<p>I'm someone that's said they'd never talk publicly. I'm slightly introvert (unless you add lager) and suffer serious bouts of imposter syndrome. For 5 years, on and off, I was in a band and you'd forever see the back of my head when we played live. The limelight was/is something that I'm not really too fussed about. As it were.</p>
<h2 id="but-i-digress..." tabindex="-1">But I Digress...</h2>
<p>However, having talked with Ant. about 12 Devs of Easter I happened upon a subject that I thought needed airing in public. I've not really taken a shine to the myriad of boilerplates, frameworks and starting points that are oozing out of the sides of this industry. The beauty of HTML/CSS in particular is you can have your own 'style' of coding and you can decide what to have and not have in your documents. In my talk I touched upon this plus other stuff. Believing that the best boilerplate is the one you write yourself. Where you borrow code from the many and adapt it so it suits how you 'write code'.</p>
<p>Sweating the details of what's in your stock HTML template or how your write your CSS (well, Sass) makes you make your code delicous.</p>
<h2 id="without-further-ado..." tabindex="-1">Without Further Ado...</h2>
<p>Here's the video</p>
<h2 id="more-than-just-me" tabindex="-1">More than just me</h2>
<p>I'd like to thank Adam and Anthony for letting me 'try my hand at this. Will I do this again? Maybe, but I'd probably have one less beer.</p>
<p>For the other talks of the evening, head over to the <a href="http://12devs.co.uk/summer-videos/">12 Devs Of Summer vide page</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Bugs, Browsers and Bookmarklets</title>
      <link href="https://www.alwaystwisted.com/articles/bugs-browsers-and-bookmarklets.html"/>
      <updated>2013-07-02T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/bugs-browsers-and-bookmarklets.html</id>
      <content type="html">
        <![CDATA[
        <p>update: Opera Next 16 fixes the ability to open a document.</p>
<p>I was watching the <a href="http://vimeo.com/69386528">'hot topics' panel discussion</a> from Mobilism yesterday where that <a href="http://www.adactio.com">Jeremy Keith</a> was regaling a story he had with an Apple devrel who said they read <a href="http://adactio.com/journal/4470/">blogposts</a> about bugs. So after the public launch of <a href="http://my.opera.com/ODIN/blog/2013/07/02/introducing-opera-15-for-desktop-and-a-fast-release-cycle">Opera 15</a>, here goes mine.</p>
<p>I've always, sort of, been a fan of clean UI of Opera but due to all the cool kids and their webkits up until Opera Next was released with Blink I stuck with Chrome and after however many days it's been I haven't really touched Chrome at all.</p>
<p>Every transition will never run as smoothly as you'd want it too. I miss my bookmarks, quite a bit. In chrome I've got a couple set up for development that I just can't darg and drop into Chrome (on research today though I think I can create my own 'extensions' for them. I'll release them if I can).</p>
<p>With any development release you should expect bugs. I found 3 or 4 and submitted them to <a href="https://bugs.opera.com/wizarddesktop/">Opera's bug tracker</a>. Here lies one problem. I don't know if I'm repeating someone elses bug report. As Opera (thus far) have chosen to have a closed doors tracking system you can't see if your bugs filed already, if someone's looking at  it, fixing it or if it's been closed. That's pretty crappy in 2013. I really hope Opera open this up, and fast.</p>
<p>As they don't have an out in the open tracking system I can't see if a bug I reported in Next which has made it through to public has been looked at or not, whether it's closed or not or what the hell they're doing about it.</p>
<p>I think the bug is pretty big. I can't open a file. [cmd] O or via the menu is just not working in the current public or next release on OS X. I think that's quite a big bug that needs squashing. So in light of today's release and listening to Jeremy on tape yesterday, I hope the developers find this post (I'll link them to it) and get this bug squashed.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Smarter RGBa fallbacks with Sass</title>
      <link href="https://www.alwaystwisted.com/articles/smarter-rgba-fallbacks-with-sass.html"/>
      <updated>2013-05-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/smarter-rgba-fallbacks-with-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>I've been working on a client site that's been making great use of colourful transparent colours for defining the main categories of their resources. The development spec also required support for Internet Explorer 8 and as we know, RGBa isn't supported so I needed a fallback.</p>
<h2 id="currently" tabindex="-1">Currently</h2>
<p>Looking at current suggestions or 'best practices' for using RGBa with a fallback for older browsers gives us the idea to use the block colour used for the RGBa as a back up, like this -</p>
<p>.element {
color: #FF0000;
color: rgba(255, 0, 0, 0.5);
}</p>
<p>I think that, although it's an acceptable answer, it's pretty crappy. You site visitors would get something that looks good on their older browser still. Wouldn't it be better to offer them a fallback colour that's closer to the transparent colour?</p>
<h2 id="colouring-function" tabindex="-1">Colouring Function</h2>
<p>So I took to codepen to thrash out a little bit of Sass which gives you the transparent colour with a (close as possible without hand coding) fallback.</p>
<p>I say it's close as possible because the transparent colour will react differently to a lighter or darker background but using a closer fallback, I think, is better than just the non-transparent colour.</p>
<p>After some playing with some code I worked out roughly what numbers I needed for both and I came to this function -</p>
<p>@function trans($color, $percentage) {
@if $percentage == .1 {
@return lighten($color, 45%);
}
@if $percentage == .2 {
@return lighten($color, 40%);
}
@if $percentage == .3 {
@return lighten($color, 35%);
}
@if $percentage == .4 {
@return lighten($color, 30%);
}
@if $percentage == .5 {
@return lighten($color, 25%);
}
@if $percentage == .6 {
@return lighten($color, 20%);
}
@if $percentage == .7 {
@return lighten($color, 15%);
}
@if $percentage == .8 {
@return lighten($color, 10%);
}
@if $percentage == .9 {
@return lighten($color, 5%);
}
}</p>
<p>This recreates a fallback colour estimated from the percentage of colour you're wanting for your transparent image where $color is the hexadecimal colour and $percentage is the a of RGBa.</p>
<h2 id="mixin-it-up" tabindex="-1">Mixin it up</h2>
<p>To get this to work I needed a little mixin to use the function when I'm needing a transparent background color or text color. So I made this for it -</p>
<p>@mixin tran($type, $color, $percentage) {
@if $type == color {
color: trans($color, $percentage);
color: rgba($color, $percentage);
}
@if $type == bg {
background-color: trans($color, $percentage);
background-color: rgba($color, $percentage);
}
}</p>
<p>Going through this we would need to define a $type, be it a background-color(bg) or just a color(color). The hexadecimal colour($color) and the level of tranparency($percentage). We could then include it in our Sass(SCSS) code like this -</p>
<p>header {
@include tran(bg, #00ff00, .8);
}</p>
<p>Which would gives us this resulting CSS -</p>
<p>header {
background-color: #33ff33;
background-color: rgba(0, 255, 0, 0.8);
}</p>
<p>Where the fallback colour is a lot closer to the RGBa than #00FF00 would be.</p>
<h2 id="close-but-no-cigar" tabindex="-1">Close but no cigar</h2>
<p>This bit of Sass(SCSS) gives us a 'close as possible' fallback. As the colour of a transparent element will change depending on the dark or light colours behind it. It's not perfect but it gives a closer fallback for your designs.</p>
<p>This is available now on <a href="http://codepen.io/sturobson/pen/cbusa">codepen to grab</a> and also now included in my Sass library <a href="https://github.com/sturobson/sassifaction">Sassifaction</a></p>
<h2 id="update---the-great-internet" tabindex="-1">UPDATE - The great internet</h2>
<p>So some hours have passed and <a href="http://twitter.com/@japborst">@japborst</a> has just submitted a lovely pull request to update the code and remove all of the @if statements. The code to get it to work for the function is now -</p>
<p>@function trans($color, $percentage, $shade) {
@return lighten($color, (1-$percentage)*5%);
}</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Sassifaction in Colour Palette Mixins</title>
      <link href="https://www.alwaystwisted.com/articles/sassifaction-in-colour-palette-mixins.html"/>
      <updated>2013-04-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/sassifaction-in-colour-palette-mixins.html</id>
      <content type="html">
        <![CDATA[
        <p>When I used to design sites as well as develop them. There was one blogpost that really helped me with my final colour choices. This was Andy Clarke's 2004 piece on creating <a href="http://www.stuffandnonsense.co.uk/archives/creating_colour_palettes.html">colour palettes</a>. At the bottom of that page (when I found it some years later) was a link to a <a href="http://slayeroffice.com/tools/color_palette/">web app</a> that created the relevant CSS hex values.</p>
<h2 id="roll-on-some-years" tabindex="-1">Roll on some years</h2>
<p>So, as I'm sure you're aware, I use Sass (SCSS). Recently I saw Andy included this colour palette idea into his <a href="http://malarkey.github.io/Rock-Hammer/">Rock Hammer project library</a>. I had a quick peek <a href="https://github.com/malarkey/rock-hammer/">under the hood</a> (or in the github repo) and saw how he was creating the colour palettes. Where he uses RGBA to give a representation of the possible colours from your primary, secondary or tertiary choices.</p>
<h2 id="to-the-pen" tabindex="-1">To the Pen</h2>
<p>I then went swiftly to a fresh codepen and created a little bit of SCSS and HTML to recreate the palettes but using Sass's tint and shade colour functions. With this pen you would pass a primary($base-color), secondary($comp-color) and tertiary($tertiary-color) set of colour variables and it would then create a nice set of colour palettes.</p>
<p>This pen, found here - <a href="http://codepen.io/sturobson/pen/haiIe">http://codepen.io/sturobson/pen/haiIe</a> - can be taken an 'dropped' into a living styleguide (note: this is all a work in progress for my own Sass 'framework' and my HTML/CSS/JS starting point).</p>
<h2 id="there's-always-a-but" tabindex="-1">There's always a but</h2>
<p>That's all well and good, it looks nice. But the way I set the page up using nth:child wasn't very good for actual use in a project so I decided to make a quick mixin.</p>
<p>This mixin has two variables within it. $color can be a hex colour or on of the variables from your styleguide or similar. There's alse $change where you'd want to lighten(tint) or darken(shade) the colour or not (which why it's predefined as 'n'. -</p>
<p>@mixin bgcolor($color, $change: n) {
@if $change == n {
background-color: $color;
}
@if $change == l1 {
background-color: tint($color, 10%);
}
@if $change == l2 {
background-color: tint($color, 25%);
}
@if $change == l3 {
background-color: tint($color, 50%);
}
@if $change == l4 {
background-color: tint($color, 75%);
}
@if $change == d1 {
background-color: shade($color, 10%);
}
@if $change == d2 {
background-color: shade($color, 25%);
}
@if $change == d3 {
background-color: shade($color, 50%);
}
@if $change == d4 {
background-color: shade($color, 75%);
}</p>
<p>}</p>
<p>So by having our chosen colours for the design set up as variables from your styleguide, for example -</p>
<p>$base-color: #D13500;
$comp-color: #398CC2;
$tertiary-color: #dd4400;
$black: #000;
$white: #FFF;</p>
<p>We can now add a background colour to an element in our CSS that's from the colour palette we've got in our styleguide and $change is how you'd want to change the $color lightening (l) or darkening (d) it in 1 of 4 possible steps.</p>
<p>To do this you'd just @include the mixin into your CSS, for example</p>
<p>.an-example {
@include bgcolor($comp-color, d3);
}</p>
<p>which would give you the compiled CSS as -</p>
<p>.an-example {
background-color: #1c4661;
}</p>
<h2 id="making-text-colourful" tabindex="-1">Making text colourful</h2>
<p>That's good for background-color, but there's probably opurtune times when you'd like to use the colour palette colours on the color element too. So for that we can create this mixin. This mixin again has two variables. Both the same as the background colour mixin -</p>
<p>@mixin color($color, $change: n) {</p>
<p>@if $change == n {
color: $color;
}
@if $change == l1 {
color: tint($color, 10%);
}
@if $change == l2 {
color: tint($color, 25%);
}
@if $change == l3 {
color: tint($color, 50%);
}
@if $change == l4 {
color: tint($color, 75%);
}
@if $change == d1 {
color: shade($color, 10%);
}
@if $change == d2 {
color: shade($color, 25%);
}
@if $change == d3 {
color: shade($color, 50%);
}
@if $change == d4 {
color: shade($color, 75%);
}</p>
<p>}</p>
<p>So we can use the mixin like this -</p>
<p>.an-example {
@include color($comp-color, d3);
}</p>
<p>which would give you the compiled CSS as -</p>
<p>.an-example {
color: #1c4661;
}</p>
<h2 id="box-it-with-borders" tabindex="-1">Box it with borders</h2>
<p>We're getting some nice mixins out of this colour palette idea. What about borders? We like using borders and perhaps we want to have border colours from the colour palette that we've decided upon.</p>
<p>So to create this I decided to also allow for top, bottom, left and right border THINGS. So with this mixin there are 5 variables. £color and $change are the same except I've given them defaults of a black colour #000 and n for $change which I've used to express no change in colour. $border-size for the border thickness, $border-style for the style and $border-position for top, bottom, left or right -</p>
<p>@mixin border($color: #000, $border-size: 1px, $border-style: solid, $border-position: null) {</p>
<p>@if $border-position == null {
@if $change == n {
border-#{$border-position}: $border-size $border-style $color;
}
@if $change == l1 {
border: $border-size $border-style #{tint($color, 10%)};
}
@if $change == l2 {
border: $border-size $border-style #{tint($color, 25%)};
}
@if $change == l3 {
border: $border-size $border-style #{tint($color, 50%)};
}
@if $change == l4 {
border: $border-size $border-style #{tint($color, 75%)};
}
@if $change == d1 {
border: $border-size $border-style #{shade($color, 10%)};
}
@if $change == d2 {
border: $border-size $border-style #{shade($color, 25%)};
}
@if $change == d3 {
border: $border-size $border-style #{shade($color, 50%)};
}
@if $change == d4 {
border: $border-size $border-style #{shade($color, 75%)};
}
}</p>
<p>@elseif $border-position != null {
@if $change == n {
border-#{$border-position}: $border-size $border-style $color;
}
@if $change == l1 {
border-#{$border-position}: $border-size $border-style #{tint($color, 10%)};
}
@if $change == l2 {
border-#{$border-position}: $border-size $border-style #{tint($color, 25%)};
}
@if $change == l3 {
border-#{$border-position}: $border-size $border-style #{tint($color, 50%)};
}
@if $change == l4 {
border-#{$border-position}: $border-size $border-style #{tint($color, 75%)};
}
@if $change == d1 {
border-#{$border-position}: $border-size $border-style #{shade($color, 10%)};
}
@if $change == d2 {
border-#{$border-position}: $border-size $border-style #{shade($color, 25%)};
}
@if $change == d3 {
border-#{$border-position}: $border-size $border-style #{shade($color, 50%)};
}
@if $change == d4 {
border-#{border-position}: $border-size $border-style #{shade($color, 75%)};
}
}</p>
<p>}</p>
<p>So for a simple border with colour you can write -</p>
<p>.an-example {
@include border($base-color, l2);
}</p>
<p>Which would give you -</p>
<p>.an-example {
border: 1px solid #dc673f;
}</p>
<p>If you wanted to create a border-top you could write -</p>
<p>.an-example {
@include border($base-color, l2, 1px, solid, top);
}</p>
<p>Would give you this resulting CSS -</p>
<p>.an-example {
border-top: 1px solid #dc673f;
}</p>
<h2 id="to-the-end" tabindex="-1">To the end</h2>
<p>So we've now got three ways of bringing our styleguides colour palette into our stylesheets. I've uploaded this to my <a href="https://github.com/sturobson/sassifaction">Sassifaction</a> Sass(SCSS) mixin library and also as a <a href="http://codepen.io/sturobson/pen/cfaFv">pen on Codepen</a>.</p>
<h2 id="update-(07%2F04%2F13)" tabindex="-1">Update (07/04/13)</h2>
<p>Almost as soon as I posted this <a href="http://twitter.com/notrenton">Ryan</a> suggested I could do this with a function instead. He went off and some minutes later came back with this -</p>
<p>@function colorize($color, $change: n) {
@if $change == n {
@return $color;
}
@if $change == l1 {
@return tint($color, 10%);
}
@if $change == l2 {
@return tint($color, 25%);
}
@if $change == l3 {
@return tint($color, 50%);
}
@if $change == l4 {
@return tint($color, 75%);
}
@if $change == d1 {
@return shade($color, 10%);
}
@if $change == d2 {
@return shade($color, 25%);
}
@if $change == d3 {
@return shade($color, 50%);
}
@if $change == d4 {
@return shade($color, 75%);
}
}</p>
<p>This lets you put the colorise function where you'd want to put color in the (S)CSS. So for example (still using our colour variables) -</p>
<p>body {
color: colorize($base-color,l4);
background: colorize(#fff,d2);
border: 1px solid colorize($comp-color,d3);
}</p>
<p>Would give you this outputted css -</p>
<p>body {
color: #f3ccbf;
background: #bfbfbf;
border: 1px solid #1c4661;
}</p>
<p>Pretty neat. I'll be updating my Sassifaction code with this great titbit of code</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>My Media Query Mixin</title>
      <link href="https://www.alwaystwisted.com/articles/my-media-query-mixin.html"/>
      <updated>2013-04-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/my-media-query-mixin.html</id>
      <content type="html">
        <![CDATA[
        <p>I've written <a href="../post.php%EF%B9%96s=2013-01-12-the-lack-of-media-queries.html">quite</a> <a href="../post.php%EF%B9%96s=2012-05-28-how-im-rolling-my-media-queries.html">a</a> <a href="../post.php%EF%B9%96s=2012-04-28-a-common-set-of-breakpoints-to-start.html">lot</a> <a href="../post.php%EF%B9%96s=2012-08-06-a-sass-mixin-for-media-queries-and-ie.html">about</a> media queries; Playing with LESS then Sass(SCSS) has made me create mixin upon mixin to help my front-end development workflow. I think I've finally settled on something (famous last words!) that works for me and want to share it. Because sharing is good, right?</p>
<h2 id="and-the-winner-is%E2%80%A6" tabindex="-1">and the winner is…</h2>
<p>@mixin mq($point, $IE9: false, $query1: min, $query2: width) {
@if $IE9 == true{
.lt-ie9 &amp; {
@content;
}
}</p>
<p>@media (#{$query1}-#{$query2}: $point / $doc-font-size +em) {
@content;
}
}</p>
<h2 id="you-say-what%3F" tabindex="-1">You say what?</h2>
<p>This mixin allows you to define your major or minor breakpoint in pixels (it automatically converts to EMs), define the media query whether it be min or max, width or height, device height or device width. The mixin has 4 variables in it, most of which are predefined.</p>
<ul>
<li>$point : is the pixel value for your major or minor breakpoint</li>
<li>$IE9 : is predefined as false, changing this to true would include the IE9 conditional class of CSS</li>
<li>$query1 : this is for either min,max, min-device, or max-device defining the first part of the media query. Predefined as min</li>
<li>$query2 : this if for either width or height defining the second part of the media query. Predefined as max.</li>
</ul>
<p>It also fantastically has the option to copy the media query content and create a snippet prefixed with an class that'd be picked up by IE8 or less as specified in your HTML with this code -</p>
<p><!--[if IE 8]> <html class='no-js lt-ie9'> <![endif]--></p>
<p>So because it can give min,max,width,height options let's go through the examples.</p>
<h2 id="what's-up-%24doc-font-size" tabindex="-1">What's up $doc-font-size</h2>
<p>In my _variables.scss I have two variables that are related to the document font-size. One for line-height and one for font-size. The $doc-font-size variable in the mixin above needs to be defined in your Sass for this to work. Mine is generally set to 16 and my variables would read</p>
<p>$doc-font-size: 16;
$doc-line-height: 24;</p>
<p>Although, we won't be using the line-height in this mixin or any examples</p>
<h2 id="examples..." tabindex="-1">Examples...</h2>
<h3 id="1)-a-simple-min-width-media-query" tabindex="-1">1) A simple min-width media query</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>@media screen and (min-width: 20em) {
.example {
width: 100%;
}
}</p>
<p>So giving the mixin no other arguements than a numeric value (a pixel value) would give you the staple media query of min-width.</p>
<h3 id="2)-a-simple-min-width-media-query-with-ie-fallback" tabindex="-1">2) A simple min-width media query with IE fallback</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, true) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>.lt-ie9 {
.example {
width: 100%;
}
}
@media screen and (min-width: 20em) {
.example {
width: 100%;
}
}</p>
<p>So giving the pixel value and the second argument as true would mean the mixin would give the CSS for your conditional IE8 class.</p>
<h3 id="3)-a-simple-max-width-media-query" tabindex="-1">3) A simple max-width media query</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, false, max) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>@media screen and (max-width: 20em) {
.example {
width: 100%;
}
}</p>
<p>Now adding the third argument of max, keeping the $IE9 variable is false creating a simple max-width media query.</p>
<h3 id="4)-a-simple-max-width-media-query-with-ie-fallback" tabindex="-1">4) A simple max-width media query with IE fallback</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, true, max) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>.lt-ie9 {
.example {
width: 100%;
}
}
@media screen and (max-width: 20em) {
.example {
width: 100%;
}
}</p>
<p>Changing the $IE9 argument to true creates a simple max-width media query plus the IE8 conditional class.</p>
<h3 id="5)-a-simple-min-height-media-query" tabindex="-1">5) A simple min-height media query</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, false, min, height) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>@media screen and (min-height: 20em) {
.example {
width: 100%;
}
}</p>
<p>By changing the forth variable to height, and stating the middle two ($IE9 and $query1) as they're defaulted in the mixin creates a simple min-height media query.</p>
<h3 id="6)-a-simple-min-height-media-query-with-ie-fallback" tabindex="-1">6) A simple min-height media query with IE fallback</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, true, min, height) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>.lt-ie9 {
.example {
width: 100%;
}
}
@media screen and (min-height: 20em) {
.example {
width: 100%;
}
}</p>
<p>Changing the second variable of the mixin ($IE9) to true would give you the simple min-height mixin with the conditional class too.</p>
<h3 id="7)-a-simple-max-height-media-query" tabindex="-1">7) A simple max-height media query</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, false, max, height) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>@media screen and (max-height: 20em) {
.example {
width: 100%;
}
}</p>
<p>Here we're keeping the IE9 variable as false, making the min/max/min-device/max-device as max and width/height as height to create a simple max-height media query.</p>
<h3 id="8)-a-simple-max-height-media-query-with-ie-fallback" tabindex="-1">8) A simple max-height media query with IE fallback</h3>
<p>So your media query you'd write in SCSS would be -</p>
<p>.example {
@include mq(320, true, max, height) {
width: 100%;
}
}</p>
<p>Which would result in -</p>
<p>.lt-ie9 {
.example {
width: 100%;
}
}</p>
<p>@media screen and (max-width: 20em) {
.example {
width: 100%;
}
}</p>
<p>Here we've just given the $IE9 variable a value of true giving a simple max-width media query and a conditional class for IE8.</p>
<p>From these examples I hope you can see that instead of min or max you can also use min-device and max-device so that you can target 'devices' if you wish to.</p>
<h2 id="major-breakpoints" tabindex="-1">Major Breakpoints</h2>
<p>I work with two kinds of CSS3 media queries in mind when developing responsive websites. Major and minor breakpoints. As mentioned in a <a href="http://www.slideshare.net/yiibu/pragmatic-responsive-design/24">slidedeck</a> from <a href="https://twitter.com/stephanierieger">Stephanie</a> and <a href="https://twitter.com/bryanrieger">Bryan</a> of <a href="http://yiibu.com/">Yiibu</a>.</p>
<p>With Sass you can create some variables for what you like to determine as 'major' breakpoints and include them as necessary in the media query mixin.</p>
<p>For example you could have predefined major breakpoints like this -</p>
<p>$mobile: 320;
$tablet: 760;
$desktop: 1200;</p>
<p>You can then include it in the mixin like this -</p>
<p>@include mq($mobile, false, max) {
.example {
width: 100%;
}
}</p>
<p>Which would give you this result -</p>
<p>@media screen and (max-width: 20em) {
.example {
width: 100%;
}
}</p>
<h2 id="nesting-that-media-query" tabindex="-1">Nesting that media query</h2>
<p>One of the great things about Sass is the ability to nest your CSS. But you can also nest mixins. This means you can nest this mixin. That's pretty cool. So as an example you can do something like this -</p>
<p>.example {
@include mq(320) {
width: 300px;
@include mq(480, false, max) {
background: red;
}
}
}</p>
<p>Would give you this result -</p>
<p>@media (min-width: 20em) {
.example {
width: 300px;
}
}</p>
<p>@media (min-width: 20em) and (max-width: 30em) {
.example {
background: red;
}
}</p>
<h2 id=".class-%3E-mixin-or-mixin-%3E-.class" tabindex="-1">.class &gt; mixin or mixin &gt; .class</h2>
<p>From all the examples I've given above I've been putting the media query mixin within the .class but you can do this the other way around and with Sass it outputs the same code. As shown in this example -</p>
<p>@include mq(320) {
.example {
width: 300px;
@include mq(480, false, max) {
background: red;
}
}
}</p>
<p>This gives the same results -</p>
<p>@media (min-width: 20em) {
.example {
width: 300px;
}
}</p>
<p>@media (min-width: 20em) and (max-width: 30em) {
.example {
background: red;
}
}</p>
<h2 id="media-query-bubbling-or-nesting" tabindex="-1">Media Query Bubbling or Nesting</h2>
<p>As I've written previously I write <a href="../post.php%EF%B9%96s=2012-05-05-everyday-im-bubbling-with-media-queries-and-less.html">my media queries 'inline'</a> with the element I'm editing rather than tagging it on to the bottom of my stylesheet. This, I feel, allows for better code organisation and a more OO 'modular' approach. This makes it easy to find the code you may need to edit and allows for a better 'mobile first' approach.</p>
<h2 id="support-for-ie6-and-7" tabindex="-1">Support for IE6 and 7</h2>
<p>There are two ways you could do this using the mixin. Forget about it like i do and plumb something like my set of <a href="https://github.com/sturobson/Universal-IE7">Universal IE7 Sass files</a> which is an updated 'Sass-ified' version of <a href="http://stuffandnonsense.co.uk/blog/about/universal_internet_explorer_6_css">Andy Clarkes Universal IE6</a> codebase. Or if you need to support IE6 and 7 a little better than that you could use <a href="../post.php%EF%B9%96s=2013-01-13-ie-fix-yoself.html">something like this</a> code snippet -</p>
<p>.lt-ie9 &amp; {</p>
<p>// put the IE8 and below CSS declarations here
/* IE8 and below */</p>
<p>// if you need IE7 as well then prefix the CSS with a *
/* IE7 and below */</p>
<p>// if you need IE6 as well then prefix the CSS with a _
/* IE6 */
}</p>
<p>Where you would be using CSS hacks to will Internet Explorer 6 and 7 into submission.</p>
<h2 id="portrait-%2F-landscape-mixin" tabindex="-1">Portrait / Landscape mixin</h2>
<p>Because you can nest media queries within each other. I've also created a little mixin for defining the portrait or landscape media query.</p>
<p>@mixin orient($orientation: landscape) {
@media (orientation : $orientation) {
@content;
}
}</p>
<p>So if you write a media query like this</p>
<p>@include mq(768) {
@include orient {
.example {
width: 100%;
}
}
}</p>
<p>It would give this result -</p>
<p>@media (min-width: 48em) and (orientation: landscape) {
.example {
width: 100%;
}
}</p>
<p>As you can see this mixin also has a variable for the landscape/portrait predefined as landscape. If you want a portrait media query you can write something like this -</p>
<p>@include mq(768) {
@include orient(portrait) {
.example {
width: 100%;
}
}
}</p>
<p>It would give this result -</p>
<p>@media (min-width: 48em) and (orientation: portrait) {
.example {
width: 100%;
}
}</p>
<p>Of course you can just include the media query by itself if you need to.</p>
<h2 id="100%25-pure-adrenaline!" tabindex="-1">100% pure adrenaline!</h2>
<p>After all this, what I've effectively done is recreate a Compass plugin by <a href="https://twitter.com/snugug">Sam</a> and <a href="https://twitter.com/codingdesigner">Mason</a> - <a href="http://breakpoint-sass.com/">Breakpoint</a>. You could say I've reinvented the wheel a little. But I like my mixin, it works for me and how I want to code. Also I don't use Compass because I like 'my own' code and to know what each mixin I use is doing. But that's just me. If you're already a Compass user your mindset might be in favour of using this plugin. As with all things, it depends.</p>
<h2 id="copy-and-paste" tabindex="-1">Copy and Paste</h2>
<p>As well as copying and pasting the code above, I've also added it on <a href="http://codepen.io/sturobson/pen/keuyp">codepen</a> and to my (work in progress (just started)) Sass mixin library - <a href="https://github.com/sturobson/sassifaction">Sassifaction</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Toggling Bad Design</title>
      <link href="https://www.alwaystwisted.com/articles/toggling-bad-design.html"/>
      <updated>2013-03-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/toggling-bad-design.html</id>
      <content type="html">
        <![CDATA[
        <p>This week has seen a flurry of posts about the possibility of adding a 'toggle' to our websites so that if a user wants to see the 'full' site they can flip a switch and the responsive design will just go away.</p>
<h2 id="we-got-ourselves-a-reader" tabindex="-1">We got ourselves a reader</h2>
<p>I remember reading Bruce Lawsons <a href="http://www.brucelawson.co.uk/2013/turning-off-responsive-web-design/">post</a> about this and stating in the comments that responsive design is <a href="http://www.brucelawson.co.uk/2013/turning-off-responsive-web-design/#comment-1275428">'more than just a technical happenstance'</a>. Later on reading Alex's post <a href="http://mistermorris.tumblr.com/post/44777883384/the-accessibility-of-media-queries-and-user-choice">about this</a> at the start of March. I thought it was a nice idea, having tweeted with Alex about it t] we both agree it should be at a 'browser' level and not something we (as designers and developers) should be worrying about.</p>
<p>This week Roger Johansson wrote <a href="http://www.456bereastreet.com/archive/201303/letting_users_disable_responsive_layout/">a post of similar ilk</a>, showing us that it's not really 'a lot of work' to implement it. Jordan Moore took this post and added <a href="http://www.jordanm.co.uk/post/46286897572/thoughts-on-toggling-a-responsive-design-on-and-off">some notes</a> to it telling us that he wished 'I had a toggle for the bad responsive designs, the ones that “don’t get it'.” and came up with an idea for icons for the user to easily choose from.</p>
<p>That Andy Clarke took Jordan's icon idea and made some more <a href="http://www.stuffandnonsense.co.uk/blog/about/a-suggestion-for-responsive-design-toggle-icons">simpler icons</a> that site visitors would moreover understand.</p>
<h2 id="unsurprisingly-me" tabindex="-1">Unsurprisingly me</h2>
<p>I (unsurprisingly) think this is a cop-out. If you think that we should be giving the site visitor the option to turn off your device agnostic design so they get a desktop view. You've not done your job correctly in the first plate.</p>
<p>As Jordan says he wants to turn off RWD on bad sites. Understandable as this is it should be something mitigated at the browser level.</p>
<p>The problem herein lies, I feel, with bad design, bad decisions and bad implementation. If you're 'doing your job' properly your responsive design should be perfect for the visitors needs so that they don't have to 'turn it off'.</p>
<p>You should be testing your designs with actual users, solving problems as best is possible. Which, may mean not even going down a responsive route. It is not a panacea.</p>
<p>We shouldn't as web designers/developers thinking of including such a toggle as it undermines the work we've created for our clients and their users. It's like asking MacDonald's to make you a double egg mcmuffin after 10.30am.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Search, it&#39;s gonna be big</title>
      <link href="https://www.alwaystwisted.com/articles/search-its-gonna-be-big.html"/>
      <updated>2013-03-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/search-its-gonna-be-big.html</id>
      <content type="html">
        <![CDATA[
        <p>The mobile device you have in your pocket or in your hand whilst reading this has, effectively, been around for a long time. I'd suggest for brevity that around 1983 when the <a href="http://en.wikipedia.org/wiki/Motorola_DynaTAC">Motorola DynaTAC</a> was launched is a good date to pick.</p>
<p>With this, I'd surmise, came a new and/or increasingly used interaction. Pushing buttons with a finger or thumb from one hand whilst holding the device in the other. So for 30 years our muscle memory has been learning and adapting to this interaction so it's essentially become a second nature.</p>
<p>Today there's more mobile phones out there that could possibly be connected to the internet than you can <a href="http://gadgets.ndtv.com/mobiles/news/samsung-apple-dominate-smartphone-sales-in-q4-2012-nokia-and-rim-aim-to-catch-up-analysts-320371">shake a stick at</a>. So the interaction between device, eyes, hands and fingers is used for swiping, tapping screens and the such.</p>
<h2 id="the-decrepit-navigation-bar" tabindex="-1">The decrepit navigation bar</h2>
<p>Since we started designing sites we included links to pages and other sites. When time moved forward and gave us opportunities to stylise these links we created horizontal and vertical 'nav bars'.</p>
<p>When the mobile device came out and we started going mobile we tailored the navigation for it. We started off making the navigation a long list realising that content was more important to a site visitor we started hiding it or moving it so that the visitor would see the content first with navigation one click/tap/pull/push/interaction away.</p>
<p>Navigation could still possibly be complex. Drop-downs turned into show and hide navigation within show and hide navigation. It seems logical, hiding it away for the visitor to find by drilling down to the link that they need.</p>
<h2 id="but-what-if-we-don't-need-the-navigation" tabindex="-1">But what if we don't need the navigation</h2>
<p>Our hands, fingers and thumbs are so used to the tactile interaction of the with a device now that I keep thinking –</p>
<blockquote>
<p>'Would asking the user to use a search form element be a better experience for them when visiting our sites?'</p>
</blockquote>
<p>A search box which we could coax into auto-suggestting the main navigation when the visitor starts typing 'about' or 'news' for example but allowing them to drill down to the content they need if the wish to.</p>
<p>This way you're not deciding what you think your user needs from your site. You're allowing them to find it and possibly find stuff they weren't aware of.</p>
<h2 id="possibly-possible%2C-it-depends" tabindex="-1">Possibly possible, it depends</h2>
<p>Of course, it depends, but who decided to have a 'main navigation bar' for sections (see chapters) of a website. A methodical way of making groups of 'pages' into something coherent on a fluid web where a visitor would (now) more often than not (I suggest) coming from a search engine.</p>
<p>Perhaps we don't need those 'main' links on some sites. Perhaps we could use 'search' as a better facilitator for narrow viewports (specifically mobile devices) where the interaction (more often than not) would be touching and tapping the glass that's displaying the website.</p>
<p>A possibility dependant.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>max-width your face off</title>
      <link href="https://www.alwaystwisted.com/articles/max-width-your-face-off.html"/>
      <updated>2013-02-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/max-width-your-face-off.html</id>
      <content type="html">
        <![CDATA[
        <p>Something I am coming across once in a while is a site that's effectively a single column up to 767 or so pixels. Personally, I find this a little lazy and would suggest time and inclination are the underlying reasons.</p>
<blockquote>
<p>'Let's just stack the content until we reach 'the iPad' at portrait'<br>
- a. developer / a. designer / a. cheque writer</p>
</blockquote>
<p>Unfortunately it's also easy to create this type of 'design' for a narrow view. A quick fix that would make your site look (possibly) lovely on a handheld device.</p>
<p>You could write something as simple as this -</p>
<p>@media (max-width: 767px) {
* {
float: none;
margin: 0;
padding: 0 10px;
width: 100%;
}
}</p>
<p>and the job would be done. Your site would now be, more or less, responsive. It could nicely stack your content in source order of your HTML.</p>
<h2 id="but-that's-crap" tabindex="-1">But that's crap</h2>
<p>In doing this what you're essentially doing is letting the browser compute all of the CSS it's downloaded then override most of it with the max-width rule. A quick (and lazy) fix with a slight performance performance issue.</p>
<p>This would (I'd surmise) be happening when you've developed from the top down. Where you'd get a .psd of the 'desktop view' and you'd have to make it responsive.</p>
<p>You can still make it responsive but you don't need to overwrite all those rules, you can still start from the ground up. It'd be a cleaner way. You'd be <a href="http://alwaystwisted.com/post.php?s=2013-01-12-the-lack-of-media-queries">using the cascade</a> for what it is rather than hacking it as an afterthought.</p>
<p>Next time, try it. It might take a little longer (budget for it) but the next time and the time after that you'd get quicker and quicker at it, if it's needed.</p>
<h2 id="more-than-your-problem" tabindex="-1">More than your problem</h2>
<p>I would argue that as a developer who only gets a 'desktop view' of the design you're only doing the best you can. We need to start educating clients that if they need a responsive site they need to be part of a reiterative process through constant communication and decision making.</p>
<p>Making second guesses as to what's needed from a site that's only got a 'desktop view' is (possibly) not going to make for a great responsive user experience.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Tools of my trade, part 1</title>
      <link href="https://www.alwaystwisted.com/articles/tools-of-my-trade-part-1.html"/>
      <updated>2013-02-11T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/tools-of-my-trade-part-1.html</id>
      <content type="html">
        <![CDATA[
        <p>So I've been (properly) freelancing for just over a month and thought it'd be nice to write a post on the hardware and software I'm using currently to make things happen.</p>
<p>This might be quite an exhaustive list of 'bits and bobs' but they're not all from within the last 30 days or so. My 'tools' have been gather over the last 3 years of 'doing web properly'. This would explain why there's so many testing devices. This is the first post, just quickly discussing the hardware I use daily.</p>
<h2 id="the-hardware" tabindex="-1">the hardware</h2>
<p><img src="/images/articles/fdde2ff060d211e2904b22000a1f8c1d7-ck.jpg" alt="my office space" loading="lazy" decoding="async"></p>
<p>I've got quite a bit of hardware which I've collected and/or purchased over the last 12 months or so. Here's a full and (slightly) detailed list.</p>
<h3 id="macbook-air" tabindex="-1">MacBook Air</h3>
<p>So my main machine is a late 2011 13' Macbook Air. It's the stock model so there's only 4GB of RAM and a 128GB hard disk. I did have a Macbook Pro but that (really) hurt my back if I ever took it with me in my bag. The Air is so light I have to check sometimes to see if I've got it.</p>
<h3 id="griffin-laptop-stand" tabindex="-1">Griffin Laptop Stand</h3>
<p>Bringing the air up around 5 inches making it that little closer to eye level for the casual glance.</p>
<h3 id="time-capsule" tabindex="-1">Time Capsule</h3>
<p>I've got a 2TB Apple Time Capsule for backing up my Air, set once and forgotten. So far, touch wood, I've not had to use it. But I'm sure there'll be a day.</p>
<h3 id="23'-monitor" tabindex="-1">23' Monitor</h3>
<p>I'm generally at my desk when I'm working so my laptop is connected to a 23' Dell Ultrasharp monitor. It's pretty good and all those extra pixels really help day in, day out. I've also got the 'sound bar' speaker system that screws onto the monitor too. Not the greatest sound in the world but after a few tweaks of the EQ in iTunes it's pretty good.</p>
<h3 id="apple-wired-keyboard%2C-magic-mouse-%26-mobee-magic-mouse-charger" tabindex="-1">Apple Wired Keyboard, Magic Mouse &amp; Mobee Magic Mouse Charger</h3>
<p>I really miss a numpad, I've used the wireless keyboard before and of course the Air doesn't have a numpad but I'm finding it really useful for doing 'all that maths' with responsive web design.<br>
Although I've got a trackpad on my Air I find that I still need to have 'a mouse' when I'm working in a 'desktop' scenario. The Magic Mouse is perfect for me for this. It's a bit weighty with two batteries installed and batteries cost a lot.<br>
I've installed the Mobee rechargeable battery to it. Makes the mouse that little bit lighter too as it only feels like there's one AA (LR6) battery inside.</p>
<h3 id="blue-snowball-usb-mic" tabindex="-1">Blue Snowball USB Mic</h3>
<p>I don't really like talking to people. Needs must when the devil drives and I've found that using this mic for Skype is perfect. It's so close to the speakers in my setup just proving that the cardioid pattern is so tight there's no feedback at all.</p>
<h3 id="usb-charger-%2F-display" tabindex="-1">USB Charger / Display</h3>
<p>I've got several devices that I test with (I'll blog about those too, soon) that need charging. I've found this little Belkin Valet USB charging 'table'. It allows you to charger 4 phones (not iPads unfortunately) and has space for 3 phones on it's surface. This works great as I've got a dock for my iPhone that connects to it. So that's a 'droid 2.2, 2.3 a WP7 phon and a iPhone all in front of me 'at the ready'.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The perils of freelancing, month one.</title>
      <link href="https://www.alwaystwisted.com/articles/the-perils-of-freelancing-month-one.html"/>
      <updated>2013-02-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-perils-of-freelancing-month-one.html</id>
      <content type="html">
        <![CDATA[
        <p>So, one month to this day I ventured out into the 'real world' and started freelancing fulltime. Leaving my old 9 to 5 job and working evenings on the side making the side job the full time gig.</p>
<p>But, what have I been up to? I'll just quickly sumarise my first month in the hope that a) I feel i've achieved something in the last 30(odd) days and b) well, take from that it what you will.</p>
<p>So,  allons-y.</p>
<h2 id="the-work" tabindex="-1">the work</h2>
<p>The jobs I've been lucky enough to be offered and take on this month have been varied. A good thing. Keeps your chops down. So what were they? In relative order of play they were...</p>
<p>I started my first month by finishing off a client project from before Christmas when I was 'just a part-timer'. The project was to create the flat HTML, CSS and JS for a site that was responsive that then would be plumbed into the back-end. This project was a great one to work on, it allowed me to really get to grips with Mixture and helped speed up my development process.</p>
<p>Whilst finishing this job off I started my first new contract for a client who specialises in emails design and strategy. Taken the designs turning them into code and making them responsive. A great continuation of a client relationship started pre-fulltime this project is still on going but hopefully it'll be signed off and live soon.</p>
<p>I also started with a short contract of retro-fitting an HTML5 audio player so that it fits viewport widths from 280px and up. The client wanted to be able to offer their clients a 'plugin-able' audio player that takes them to the host site to buy audio tracks. This was great. I learnt alot about iframes, what you can and can't do with them and managed to create a solution true to the players original design and I only touched the CSS.</p>
<p>Next up, was a learning lesson. An 'out of the blue' email, a flurry of skype conversations and a small gig to create a responsive pagination pattern. All went well. Day three on the project I got 'an inkling'. The client went hot and cold and thus far I've had not further conversation with them. You could mark this down as part of the learning curve. Getting things in stone etc. I know. This was a moment of madness where I forgot 'contracts' and the such. I did learn lots though, every cloud.</p>
<h2 id="the-outgoings" tabindex="-1">the outgoings</h2>
<p>As well as my nominal monthly out goings for the business. I've also spent some money on 'things'. I've purchased an old Nokia S60 device for the test suite and I also nabbed a ticket to the ampersand conference down in Brighton.</p>
<h2 id="closing-notes" tabindex="-1">closing notes</h2>
<p>So that's pretty much my first month. Down on paper it seems like I've hardly 'done' anything. I'm sure I've missed stuff and I've no doubt been as verbose as I could have been, but this was an attempt to summarise after all.</p>
<p>And, how have you been?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>More Podcasts than you can shake a stick at</title>
      <link href="https://www.alwaystwisted.com/articles/more-podcasts-than-you-can-shake-a-stick-at.html"/>
      <updated>2013-01-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/more-podcasts-than-you-can-shake-a-stick-at.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in April last year I wrote a short post <a href="http://alwaystwisted.com/post.php?s=2012-04-07-listen-everyday">gathering together some podcasts</a> I listen to. It seems thus far that 2013 is turning out to be a year for podcasts. <a href="https://twitter.com/StuRobson/status/291107846676967424">That's amazing!</a>. Here's a list of podcasts that you should now give your grubby ears the joy of listening to.</p>
<h2 id="besquare" tabindex="-1"><a href="http://www.besquare.me/podcasts/">BeSquare</a></h2>
<p>As well as <a href="http://twitter.com/craiginwales">@craiginwales</a> fantastic resource of collection conference videos you couldn't get to go to. He's also been creating some video and audio podcast interviews with some stalwarts of the industry</p>
<h2 id="happy-monday-podcast" tabindex="-1"><a href="http://happymondaypodcast.com/">Happy Monday Podcast</a></h2>
<p>A new, short-burst, industry podcast available every Monday from 7am GMT from <a href="http://twitter.com/sazzy">@sazzy</a> and <a href="http://twitter.com/joshlong">@joshlong</a></p>
<h2 id="the-back-to-front-show" tabindex="-1"><a href="http://backtofrontshow.com/">The Back to Front Show</a></h2>
<p>Weekly 'web focused' musings from <a href="https://twitter.com/keirwhitaker">@keirwhitaker</a> and <a href="http://twitter.com/kieranmasterton">@kieranmasterton</a></p>
<h2 id="less-than-bang" tabindex="-1"><a href="http://lessthanbang.com/">Less Than Bang</a></h2>
<p>A show by and for young &amp; attractive web people from <a href="http://twitter.com/pauladamdavis">@pauladamdavis</a> and <a href="http://twitter.com/phuunet">@phuunet</a></p>
<h2 id="unfinished-business" tabindex="-1"><a href="http://unfinished.bz/">Unfinished Business</a></h2>
<p>From <a href="http://twitter.com/malarkey">@malarkey</a> and <a href="http://twitter.com/annadebenham">@annadebenham</a> discussing the business side of web things</p>
<h2 id="quit!" tabindex="-1"><a href="http://5by5.tv/quit">Quit!</a></h2>
<p>From podcast mogul <a href="http://twitter.com/danbenjamin">@danbenjamin</a>, a live call-in show helping people sort their lives out.</p>
<h2 id="the-web-ahead" tabindex="-1"><a href="http://5by5.tv/webahead">The Web Ahead</a></h2>
<p>Another <a href="http://5by5.tv">5by5.tv</a> show hosted by <a href="http://twitter.com/jensimmons">@jensimmons</a> talking all things relevant and topical in the web. Bonus: includes 'The Web Behind' with co-host <a href="http://twitter.com/meyerweb">@meyerweb</a> talking about the history of the web</p>
<h2 id="bizcraft" tabindex="-1"><a href="http://unmatchedstyle.com/bizcraft">BizCraft</a></h2>
<p>Another business-side podcast that's worthy of a listen.</p>
<h2 id="upfront-podcast" tabindex="-1"><a href="http://upfrontpodcast.com/">Upfront Podcast</a></h2>
<p>A weekly web development podcast by <a href="http://twitter.com/Jack_Franklin">@Jack_Franklin</a> and <a href="http://twitter.com/benhowdle">@benhowdle</a>.</p>
<h2 id="the-port80-podcast" tabindex="-1"><a href="http://port80events.co.uk/podcasts/">The Port80 Podcast</a></h2>
<p>Where <a href="http://twitter.com/joel_hughes">@joel_hughes</a> talks to 'various web folk about the stuff they do and why they do it.'</p>
<p>These are 'out' but there's a couple to keep an eye out for too...</p>
<h2 id="beyond-ink" tabindex="-1"><a href="http://beyondink.co.uk/">Beyond Ink</a></h2>
<p>From <a href="http://twitter.com/missrachilli">@missrachilli</a> and coming soon a new web-design podcast that aims to help us understand our craft more than ever before</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>IE Fix Yo&#39;self!</title>
      <link href="https://www.alwaystwisted.com/articles/ie-fix-yoself.html"/>
      <updated>2013-01-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/ie-fix-yoself.html</id>
      <content type="html">
        <![CDATA[
        <p>A while back I was developing a site and got to thinking about the conditional classes I was using in my HTML to allow me to specific 'fixes' for IE6,7 &amp; 8.</p>
<p>It seemed a little verbose to have 3 lines at the top of my HTML document 'just in case' a visitor was using an older browser.</p>
<h2 id="to-the-internet!" tabindex="-1">To the internet!</h2>
<p>I went a googling and came across this post from <a href="http://twitter.com/mathias">@mathias</a> - <a href="http://mathiasbynens.be/notes/safe-css-hacks">In defense of CSS hacks</a> and was convinced that applying hacks to the CSS as and when needed would be much nicer for my development process (and sanity).</p>
<h2 id="pen-it." tabindex="-1">Pen it.</h2>
<p>So I threw open a new <a href="http://twitter.com/codepen">@codepen</a> and created - <a href="http://codepen.io/sturobson/pen/oJEwg">IE fix yo'self</a>. It's a snippet for my pre-processor of choice (Sass (SCSS syntax)). I've got it set up in Coda 2 now so that I can quickly get that 'template' up and running as soon as possible and allow me to 'hack' if needed IE6 &amp; 7.</p>
<p>It looks like this -</p>
<p>.an-example {</p>
<p>// put the IE9 and 'other' browser CSS declarations here</p>
<p>.lt-ie9 &amp; {</p>
<p>// put the IE8 and below CSS declarations here
/* IE8 and below */</p>
<p>// if you need IE7 as well then prefix the CSS with a *
/* IE7 and below */</p>
<p>// if you need IE6 as well then prefix the CSS with a _
/* IE6 */</p>
<p>}
}</p>
<h2 id="386'ing-(not-really)" tabindex="-1">386'ing (not really)</h2>
<p>Today I saw a tweet from the <a href="http://twitter.com/H5BP">HTML5 boilerplate</a> account <a href="https://twitter.com/h5bp/status/290530820370866177">saying</a> they've opened <a href="https://github.com/h5bp/html5-boilerplate/issues/1290">a discussion about 'dropping' conditional class support for IE</a> which reminded me of this snippet.</p>
<p>I think it's <a href="https://github.com/h5bp/html5-boilerplate/issues/1290#issuecomment-12201585">probably a good thing</a> for the boilerplate to drop support for conditional classes. But hope they point developers as to the reasons why and how to 'hack' around it. Using something like the code example above.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The lack of media queries</title>
      <link href="https://www.alwaystwisted.com/articles/the-lack-of-media-queries.html"/>
      <updated>2013-01-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-lack-of-media-queries.html</id>
      <content type="html">
        <![CDATA[
        <p>In a <a href="http://www.slideshare.net/bryanrieger/rethinking-the-mobile-web-by-yiibu">Yiibu presentation</a> from September 2010 slide <a href="http://www.slideshare.net/bryanrieger/rethinking-the-mobile-web-by-yiibu/79">79</a>, had this sentence.</p>
<p>'the absence of support for @media queries is in fact the first @media query…'</p>
<p>So any browser on any machine that doesn't support media queries will have this one true 'media query' from the outset.</p>
<h2 id="have-i-told-you-lately%3F" tabindex="-1">Have I told you lately?</h2>
<p>What I'm seeing lately are designs created from 320 pixels and upwards (not Andy's fantastic boilerplate). Which is great if your have a browser viewport that's 320px wide. But 'the mobile web' doesn't start at 320px.</p>
<p>Recently <a href="http://twitter.com/snugug">Sam Richard</a> posted an overview of his <a href="http://snugug.com/musings/amusing-analytics-december">browser statistics for December 2012</a>. Although screen resolution doesn't necessarily equate to a devices viewport. You could easily be breaking your site if you only start optimising the design from 320px.</p>
<h2 id="baseline-first" tabindex="-1">Baseline first</h2>
<p>On January 9th <a href="http://twitter.com/adactio">Jeremy</a> wrote a <a href="http://adactio.com/journal/5964/">brief musing</a> on supporting IE in a media queried world. In it he mentions 'linearised content with baseline styles'. That is what we should be doing first.</p>
<p>In the code.</p>
<p>Before you even think about the layout on your popular device from 320 and up code as if the design is a complete 'stack and scroll' device.</p>
<h2 id="basics-first" tabindex="-1">Basics First</h2>
<p>Add your HTML, include your reset then only add font sizes, families, weights. Include colours and minimal margins and paddings to your CSS. Don't float. Don't make a horizontal navigation. No gradients, no rounded corners. Just the basics.</p>
<h2 id="doit.gif" tabindex="-1">doit.gif</h2>
<p>Doing this will give you good stead for the devices and browsers that don't support media queries and the ones that do but are smaller than 320px.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Don&#39;t do this in responsive web development</title>
      <link href="https://www.alwaystwisted.com/articles/dont-do-this-in-responsive-web-development.html"/>
      <updated>2013-01-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/dont-do-this-in-responsive-web-development.html</id>
      <content type="html">
        <![CDATA[
        <p>I've just read this article from <a href="http://twitter.com/netmag">@netmag</a> on how to <a href="http://www.netmagazine.com/tutorials/build-basic-responsive-site-css">'build a responsive site with CSS'</a> and wanted to quickly share something.</p>
<p>In the post (a republication of an article they printed in June/July of 2012) they quickly discuss the meta tag for <a href="https://developer.mozilla.org/en-US/docs/Mobile/Viewport_meta_tag">viewport</a>.</p>
<p>In the example code they use the maximum-scale, like this –</p>
<p><meta name='viewport' content='width=device-width, minimum-scale=1.0, maximum-scale=1.0' /></p>
<p>This stops the user from zooming into your site. Yes you've designed it and coded it for a narrow viewport from something like an iPhone. That doesn't mean the sites visitor doesn't want to zoom in, perhaps they have difficulty with their sight.</p>
<p>So please. Don't include that. Use this instead –</p>
<p><code>&lt;meta name='viewport' content='width=device-width, minimum-scale=1.0' /&gt;</code></p>
<p><meta name='viewport' content='width=device-width, initial-scale=1.0' /></p>
<p>This means the visitor can zoom into the site (perhaps to take a finer look at a photo) and is a quick accessibilty win.</p>
<h2 id="update." tabindex="-1">Update.</h2>
<p>I was asked on twitter how I handle the <a href="https://twitter.com/Sheerman/status/289339346937597952">'orientation-change zoom-screwery'</a> I mentioned that (thus far) I've not found any botheration from clients that it does this (sidenote: perhaps it's a 'developer thing').</p>
<p>But there is a fix from the guys at <a href="http://twitter.com/filamentgroup">Filament Group</a> using Javascript which is discussed in <a href="http://filamentgroup.com/lab/a_fix_for_the_ios_orientationchange_zoom_bug/">this fine blogpost</a> from <a href="http://twitter.com/scottjehl">Scott Jehl</a>.</p>
<h2 id="update-updated." tabindex="-1">Update Updated.</h2>
<p>I had a quick tweet from @snugug reminding me that the orientation bug is fixed in iOS 6+ and recommending using initial-scale rather than minimum-scale (which I agree with and have updated the post).</p>
<h2 id="update%2C-update-updated." tabindex="-1">Update, Update Updated.</h2>
<p>On the 23rd of October I looked into the code of a newly launched site to see</p>
<p><meta name='viewport' content='user-scalable=no, width=device-width, minimum-scale=1.0, maximum-scale=1.0' /></p>
<p>Needless to say, don't do that either. Adding:</p>
<p>user-scalable=no</p>
<p>Is just as bad.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Develop your styleguides with code</title>
      <link href="https://www.alwaystwisted.com/articles/develop-your-styleguides-with-code.html"/>
      <updated>2013-01-10T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/develop-your-styleguides-with-code.html</id>
      <content type="html">
        <![CDATA[
        <p>I've recently read a lovely post by <a href="http://twitter.com/markboulton">Mark Boulton</a> where he touches on our <a href="http://markboulton.co.uk/journal/abstractions">current fascination</a> with styleguides, pattern libraries and primers.</p>
<p>I'd like to give my take on it.</p>
<p>I'm just going to ratify what I often say and that is I'm not a designer. I just can't do it as good as other people so I don't.</p>
<p>I love HTML, CSS and JS (kinda) and (blowing my own trumpet) I'm pretty good at it.</p>
<h2 id="frickin'-love-styleguides" tabindex="-1">Frickin' love styleguides</h2>
<p>Or pattern libraries, or <a href="http://adactio.com/journal/5028/">pattern primers</a>. They help me code more effeciently in that object orientated kind of way. I don't mean I need a .psd file of 'all the things'.</p>
<p>How I approach creating a coded styleguide is pretty basic.</p>
<ol>
<li>print out 'pages' in grayscale</li>
<li>attach tracing paper</li>
<li>make pretty boxes</li>
<li>define naming convention</li>
<li>start coding</li>
<li>re-iterate</li>
<li>re-iterate</li>
</ol>
<p>This stops me from duplicating code and allows me to check changes 'globally'.</p>
<h2 id="be-appropriate" tabindex="-1">Be appropriate</h2>
<p>I think styleguides as I seem them in web design are for the developer more than the designer. I feel the designer should be thinking about the 'bigger picture' in fixing the problem for their client.</p>
<p>The developer should be making their best effor in coding it as leanly, cleanly as possible. To get that you should really be trying to make a pattern library or <a href="https://github.com/snugug/style-sites">styleguide</a> with your code.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Structuring my Sass 101, part 3.</title>
      <link href="https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-3.html"/>
      <updated>2013-01-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-3.html</id>
      <content type="html">
        <![CDATA[
        <p>note: This is not a guide. This is just how I choose to do things.</p>
<p>In the first post I discussed <a href="http://alwaystwisted.com/post.php?s=2013-01-07-structuring-my-sass-101-part-1">my file structure</a>, in the 2nd I gave a brief overview of how I <a href="http://alwaystwisted.com/post.php?s=2013-01-07-structuring-my-sass-101-part-2">import everything for compiling my CSS</a>.</p>
<p>In this post I'm going to discuss my _variables.scss file and my (personal) _mixins.scss file.</p>
<h2 id="_variables.scss" tabindex="-1">_variables.scss</h2>
<p>This is pretty self explanitory really. In this file I keep all the Sass variables that I'd be using throughout the project. So this could include colors, font-families, initial document settings (like font-size and line-height), gutters.</p>
<p>These individual variables are grouped and seperated  by a comment. So it would look something like this.</p>
<p>// initial variables set-up</p>
<p>$doc-font-size:16;
$doc-line-height:24;</p>
<p>// gutter for grids</p>
<p>$gutter: 2.1666667%;</p>
<p>// colors</p>
<p>$dark-grey: #5e5e5e;
$dark-red: #b50000;</p>
<p>// font family</p>
<p>$header-font:	'futura-pt',sans-serif;
$content-font:	'proxima-nova',sans-serif;</p>
<p>This file is opened once in a while, for adding things usually. Keeping all my variables in one place means I won't have to hunt for it later when I see it referenced but can't find it to change it.</p>
<h2 id="_mixins.scss" tabindex="-1">_mixins.scss</h2>
<p>Using a file like this you can tell that I don't use something like Compass or Bourbon (unless required by a client). This is because I like to write my own mixins so I know what the mixin does and how it'll nicely output when compiled. So this file is where I keep my font-size mixin for REMs w/ a px fallback that I can also set or auto-create the line height and bottom margin for. There's a function for just creating the font-size REM w/ a px fallback. A mixin for setting a sprite file location and basic setup for using with :before and much more.</p>
<p>Even if you use Compass or Bourbon I bet there's a time where you'd need something custom, just for your current project. Stick it in there and if you need to edit it. You'll know where it is.</p>
<h2 id="recap-%26-onwards" tabindex="-1">Recap &amp; Onwards</h2>
<p>In this post I've touched on what I include in my variables and mixins files. Helping me keep things sane and seperate in my Sass. In the next post I'll go over my _helper.scss and _debug.scss files where I make the HTML5 boilerplate helpers mixins so I can add them into my CSS and not my HTML (i'll get to my reasons why, soon).</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Structuring my Sass 101, part 2.</title>
      <link href="https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-2.html"/>
      <updated>2013-01-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-2.html</id>
      <content type="html">
        <![CDATA[
        <p>note: This is not a guide. This is just how I choose to do things.</p>
<h2 id="part-2%2C-compiling" tabindex="-1">Part 2, Compiling</h2>
<p>In the last post I quickly discussed my <a href="http://alwaystwisted.com/post.php?s=2013-01-07-structuring-my-sass-101-part-1">folder structure</a>, in this post I'm going to talk you through my basic set of files and how the yall compile to styles.scss.</p>
<p>So here's my folder structure -</p>
<p><img src="http://alwaystwisted.com/perch/resources/screen-shot-20130107-at-22.18.54-ck.png" alt="" loading="lazy" decoding="async"></p>
<p>Let's start with the main file that imports everything - styles.scss</p>
<h2 id="import-it-all-and-import-it-now" tabindex="-1">Import it all and import it now</h2>
<p>So the code within the styles.scss file looks like this</p>
<p>/*
-----------------------------------------------------
CSS file for cool client name here
Media: ALL THE THINGS</p>
<p>Author: Stuart Robson</p>
<p>-----------------------------------------------------
*/</p>
<p>// Normalize</p>
<p>@import 'defaults/_normalize.scss';</p>
<p>// Helpers</p>
<p>@import 'defaults/_helpers.scss';</p>
<p>// Mixins</p>
<p>@import 'defaults/_mixins.scss';</p>
<p>// Variables</p>
<p>@import 'defaults/_variables.scss';</p>
<p>// Grid System</p>
<p>@import 'partials/_grids.scss';</p>
<p>// Base</p>
<p>@import 'defaults/_base.scss';</p>
<p>// Put Your stuff here</p>
<p>@import '_page.scss';</p>
<p>// Internet Explorer Specific fixes</p>
<p>@import 'partials/_ie.scss';</p>
<p>// Print styles</p>
<p>@import 'defaults/_print.scss';</p>
<p>// DEBUG MODE</p>
<p>$debugMode:         false;</p>
<p>@import 'defaults/_debug.scss';</p>
<p>So, in this code you can see what I'm importing. There are a few things to note. The _helpers.scss is a set of @mixins that I currently have that I include into the compiled CSS rather than the HTML (that's a whole different blog post as to why).</p>
<p>There are two files that I keep in the 'partials' folder that are included in this 'master' import scss file. The _grids.scs file although 'generic' may have me putting things in specific to the site I'm working on as well as the default setup. Likewise the _ie.scss file, although always included in a project. I may decided to add specific IE CSS rules here (although this is rare now (another blog post).</p>
<h2 id="what's-on-the-_page" tabindex="-1">What's on the _page</h2>
<p>The _page.scss file (I might change that to _system.scss or something) is where I put any site specific scss files which would be taken from with the partials folder.</p>
<h2 id="recap-%26-onwards" tabindex="-1">Recap &amp; Onwards</h2>
<p>So I've touched on how I get my scss files importing with each other and compiling to a lovely styles.css file. Next up I'll go over my _mixins.scss and _variable.scss files with the whats and hows of the code therein.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Structuring my Sass 101, part 1.</title>
      <link href="https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-1.html"/>
      <updated>2013-01-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/structuring-my-sass-101-part-1.html</id>
      <content type="html">
        <![CDATA[
        <p>note: This is not a guide. This is just how I choose to do things.</p>
<p>I've been meaning to write more about how I structure my Sass files when front-end dev'ing for clients. I was going to do this huge long post but I kept finding that idea daunting.</p>
<p>The plan is to have several short posts discussing bits of the whole that'll eventually make 'the whole'.</p>
<h2 id="part-1%2C-folder-structure" tabindex="-1">Part 1, Folder Structure</h2>
<p>I keep my Sass folder within my CSS folder. Using something like codekit you can choose to do this differently, but for me this is just easier.</p>
<p>So I'd have a CSS folder, where the compiled SCSS would end up, and a folder called SCSS. In that folder there's a further two, defaults and partials.</p>
<p><img src="/images/articles/screen-shot-20130107-at-22.12.43-ck.png" alt="folder structure" loading="lazy" decoding="async"></p>
<p>The 'defaults' folder is where I'd keep things that would never or very rarely change during the projects lifetime. This is where your reset would go, your print styles and your helpers.</p>
<p><img src="/images/articles/screen-shot-20130107-at-22.18.54-ck.png" alt="Sass folder fully open" loading="lazy" decoding="async"></p>
<p>In the image above there are two files that you'd probably have open for the start of a project and at times during it. These are the _variables.scss file and the _mixins.scss file (more on this in a future post).</p>
<h2 id="compiling" tabindex="-1">Compiling</h2>
<p>Hopefully you can see from the above image how everything gets compiled via styles.scss into styles.css (again more on this in a future post).</p>
<h2 id="recap-%26-onwards" tabindex="-1">Recap &amp; Onwards</h2>
<p>So, quite a short post. Just how I lay my folders and files out when I'm getting my pre-processing going on. In the next post of this little series I'll go through how and what I'm importing and where in the SCSS files to get my nicely outputted CSS up and running.</p>
<p><a href="http://alwaystwisted.com/post.php?s=2013-01-07-structuring-my-sass-101-part-2">Go to part two of this series</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>monthly web services costs</title>
      <link href="https://www.alwaystwisted.com/articles/monthly-web-services-costs.html"/>
      <updated>2013-01-04T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/monthly-web-services-costs.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="shit%2C-how-much%3F" tabindex="-1">shit, how much?</h2>
<p>So, back in October <a href="http://twitter.com/chriscoyier">Chris Coyier</a> wrote a post <a href="http://css-tricks.com/web-developer-economics-monthly-service-costs/">laying out his monthly costs</a> for services he uses. I've been meaning to do this post in reply ever since. Now that I've started freelancing full time I thought it quite apt to write it.</p>
<h3 id="eukhost-ltd.---%C2%A38.99" tabindex="-1"><a href="http://www.eukhost.com/">EUKHost Ltd.</a> - £8.99</h3>
<p>I've been using EUKHost since 2006, I'm on an old legacy pricing structure on a shared linux server. It's pretty good, I've never noticed downtime and their status is generally 99.6% uptime. I've also (thus far) not broken it whilst being 'SmasingMag-ed' or 'Zeldman-ed'. It does me good, and it's cheap.</p>
<h3 id="github-(small-plan)---%C2%A34.40-(ish)" tabindex="-1"><a href="https://github.com/">GitHub</a> (small plan) - £4.40 (ish)</h3>
<p>Github hosts the code for rwdcalc.com but I also use it for creating private repos for client work as a kind of backup. I'm probably over thinking that bit. It's also privately hosting my boilerplate. A constant work in progress before release.</p>
<h3 id="browserstack---%C2%A312.14-(ish)" tabindex="-1"><a href="https://www.browserstack.com/">Browserstack</a> - £12.14 (ish)</h3>
<p>Unlike Chris, I do have a VM or two but sometimes it's just quicker to user Browserstack. Since it's recent UI update it feels faster and it works perfectly with localhost testing of site using mixture.io's content injecting for older browsers (no refresh needed for &lt;IE8).</p>
<h3 id="adobe-creative-cloud---%C2%A327.34-(ish)" tabindex="-1"><a href="http://www.adobe.com/uk/products/creativecloud.html">Adobe Creative Cloud</a> - £27.34 (ish)</h3>
<p>There was an email that I got giving me this real cheap for the first year if I upgraded from my Photoshop CS6 on-going payment. I couldn't say no. This means I've now got typekit tied to this payment rather than seperate.</p>
<h3 id="internet-access---%C2%A328.95-%26-%C2%A315.00" tabindex="-1">Internet Access - £28.95 &amp; £15.00</h3>
<p>I've got a broadband line in the house where I'm doing most of my work but I've also got a mifi for when I'm out and about and travelling. For £15 a month I get 10gb of mifi data access with Three. Pretty good coverage but when it drops whilst I'm commuting. Dang!</p>
<h3 id="freeagent---%C2%A316.20-(currently)" tabindex="-1"><a href="http://www.freeagent.com/?referrer=41kfq5bv">Freeagent</a> - £16.20 (currently)</h3>
<p>I'm not really sure if this 'fits' in this list. I think it does, it's a service that I pay for monthly and it's pretty important to me to help me 'keep my house' in order.</p>
<h2 id="to-total---%C2%A3113.02-(ish)" tabindex="-1">To Total - £113.02 (ish)</h2>
<p>Adding all that up works out at £113.02 (ish) a month. Less than I was expecting at almost half of that is internet access (quite vital).</p>
<h2 id="share" tabindex="-1">Share</h2>
<p>Like Chris states in his post, it'd be nice to hear what your costs are and why you 'need' it to work each month.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Another turning point, a fork stuck in the road.</title>
      <link href="https://www.alwaystwisted.com/articles/another-turning-point-a-fork-stuck-in-the-road.html"/>
      <updated>2012-12-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/another-turning-point-a-fork-stuck-in-the-road.html</id>
      <content type="html">
        <![CDATA[
        <p>Day One.</p>
<p>This is it I guess. My first day of 'properly' freelancing.</p>
<p>Let's see how this goes.</p>
<p>To paraphrase Green Day, I hope I have the time of my life.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Get in the mix</title>
      <link href="https://www.alwaystwisted.com/articles/get-in-the-mix.html"/>
      <updated>2012-12-09T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/get-in-the-mix.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/mixture-ck.gif" alt="mixture logo" loading="lazy" decoding="async"></p>
<p>So there's been quite a flurry of tweets tonight about <a href="http://mixture.io">Mixture</a>. I'm sure you'll know if you follow me on twitter I frickin' love it. So in this brief post I hope to explain how it helps me.</p>
<h2 id="the-obligatory-back-story" tabindex="-1">the obligatory back story</h2>
<p>So, I'm a front-end developer. I don't design. I rarely dare touch anything to do with that 'back-end' (insert Kenneth Williams gif here). I generally take a clients designs and make them look bloody gorgeous across a bounty of devices at a plethora of speeds, but I digress.</p>
<h2 id="team-mixture" tabindex="-1">Team Mixture</h2>
<p>I've been using Mixture for the last 5-6 weeks (of evenings) for a client site. It's not the biggest site in the world but it'd be fairly sizeable once what I'm coding gets plumbed into the 'back-end' (another gif) and all the content is added in.</p>
<p>{please note: Mixture is not a code editor).</p>
<h2 id="html%2F.liquid-craziness" tabindex="-1">HTML/.liquid craziness</h2>
<p>So with Mixture I've managed to do something I think is amazing. I've managed to<br>
create 'bits' of HTML that I can then tie into different pages of the site as and when needed. I can override parts of the page with other 'bits' so I can write once, use anywhere on a site I'm developing. That's pretty speedy. It's really easy to refactor, edit and make your code better across a whole site in a blink of an eye.</p>
<p><a href="http://docs.mixture.io/templates">Docs for Mixtures templating awesomeness</a></p>
<h2 id="sass%2Fless%2Fstylus" tabindex="-1">Sass/LESS/Stylus</h2>
<p>I love me some pre-processing. Mixture tries to cater for all allowing you to write your CSS dry, with Sass, LESS or Stylus. That's pretty open. It also includes Compass and Bourbon so Sass/SCSS users are well catered for. Allowing me to choose what language I want to pre-process in is pretty nice rather than 'being told'. Not a CSS pre-processor but Mixture also allows from CoffeeScript too.</p>
<p><a href="http://docs.mixture.io/preprocessors">Docs for Mixtures pre-processor funtimes</a></p>
<h2 id="optimisation" tabindex="-1">Optimisation</h2>
<p>Image optimisation, debugging and CSS/JS minifying is built in.</p>
<p>Docs on Optimisation</p>
<h2 id="boilerpates" tabindex="-1">Boilerpates</h2>
<p>Opening up Mixture allows you to create a project. This could be blank but what's great is that it includes so boilerplates/frameworks to get you going. It's got a Compass boilerplate. Inuit.css from Harry Roberts, the Twitter Bootstrap and soon (I think) you'll be able to add your own to get you going even quicker.</p>
<h2 id="to-do" tabindex="-1">To-Do</h2>
<p>So I'm coding a part of a page and I do something I want to get back to. Mixture has a todo built in. I can place a 'todo' on any page and the app keeps a tally and allows me to 'jump to' a todo from within in it. That's great if you need to quickly use a 'magic number' for something or want to press on and come back to it later. The todo part of the app is excellent.</p>
<h2 id="local-host" tabindex="-1">Local Host</h2>
<p>'Out of the box' Mixture has created a virtual host server for my project. I can edit some details in a file (easily) and be able to access the project Mixture is running on all my devices. That's pretty good for testing on not only other browsers (IE for example) but also devices.</p>
<h2 id="'staging'-server" tabindex="-1">'staging' server</h2>
<p>Mixture also creates a 'staging' server so that you can upload what you're working on. This is awesome for client approval, checking etc. My client can now open the Android phones browser and check out how their site is looking, how's it coming along. You could even use this for demo-ing ideas you have for certain aspects, like a mobile navigation pattern.</p>
<h2 id="live-reload-'all-the-things'" tabindex="-1">Live Reload 'all the things'</h2>
<p>LiveReload is baked in and the team at Mixture have bettered it so that it works on ALL* browsers including good ol' Internet Explorer 6, 7, 8, 9 and on any Android stock browser. I've done this with my Air, iPhone (chrome iOS), Nexus 7 (Opera Mobile) and Huawei Blaze (Android 2.3 stock browser). That's great to help you quickly test, locally, how you site'd look with your device test suite/lab.</p>
<p>*except Opera mini, because, you know...</p>
<p>Here's a video from Neil <a href="http://www.youtube.com/watch?feature=player_embedded&amp;v=yOM2_UATlWw">testing out 'live reload' on some devices that do and don't support LiveReload</a>.</p>
<p><a href="http://docs.mixture.io/mixture">Docs for boilerplates, todo, local and online settings</a></p>
<h2 id="exports-to-html" tabindex="-1">Exports to HTML</h2>
<p>Yep, does that. So all you @includes, ifs and everything get 'compiled' into a full on static site.</p>
<h2 id="justice" tabindex="-1">Justice</h2>
<p>I've probably not done the product justice, but it's awesome.</p>
<p>If you've not signed up <a href="http://mixture.io/">then do it</a> (insert my favourite gif here). If you've a question I guess you'd best ask <a href="http://twitter.com/neiltak">Neil</a>, you could ask me but I'm sure I'm only touching the surface of it's power.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>What and how I support browsers</title>
      <link href="https://www.alwaystwisted.com/articles/what-and-how-i-support-browsers.html"/>
      <updated>2012-10-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/what-and-how-i-support-browsers.html</id>
      <content type="html">
        <![CDATA[
        <p>I was perusing the twitters today, as I do, and came across a tweet about the twitter bootstrap framework and it's support (or lack of) for Microsoft's internet explorer. This got me wanting to write this post but there's also another reason why I'm about to blabber on about support (which I hope you'll read).</p>
<h2 id="january" tabindex="-1">January</h2>
<p>If you've <a href="http://www.twitter.com/sturobson">followed me on twitter</a> or we've spoken, you'll know that I'm 'giving up' client work until January 2013 so I can re-adress where I want to be, what I want to do and by when I want to get thing s rolling.</p>
<p>Hopefully in January 2013 I'll have a new version of this site with more 'about me/hire me' shizzle to 'drum up some trade', a new design of RWDCalc will be out, I hope to have something happening with deCSSor and all will be good.</p>
<p>On my process to get there I think it'd be a good idea to document some bits on the way. I guess this'll be the first one.</p>
<h2 id="i-digress-(i-do-that)" tabindex="-1">I digress (I do that)</h2>
<p>So, browsers &amp; the support thereof. Weekly? Daily? Hourly or at least sometimes I see conversations regarding browser support and phrases like 'we don't support IE7 but support IE8 and up' or similar. At face value such a phrase doesn't mean anything (I feel).</p>
<p>You don't support IE7 so they just get a blank page?</p>
<p>If so, that's ridiculous.</p>
<p>If you code sites correctly there's a chance that it'll be useabe in quite a few browsers and there in lies the need for clarification of the word 'support'.</p>
<h2 id="support" tabindex="-1">Support</h2>
<p>If you stipulate what browsers you 'support' you need to define that level of 'support'. Pixel perfection? It'll look a little different but it'll work the same? There'll be a couple of sections that won't work for a certain browser but you do this to rectify it and so on.</p>
<p>As we know the answer to <a href="http://dowebsitesneedtolookexactlythesameineverybrowser.com/">'Do websites need to look exactly the same in every browser?'</a> the interaction doesn't have to be the exactly same either, does it. If I'm supporting mobileSafari and Opera mini do I have to have a flyout menu for both browsers? I'd say no. As Opera mini is a proxy browser and is tied down with what JS can be done with it perhaps give Opera mini a nav at the bottom of the 'page' or just under the heading instead of something that'd rely on JS that'd reload the page.</p>
<h2 id="definitions" tabindex="-1">Definitions</h2>
<p>Of course, with all things, I'd say this is project dependant too. I don't think you can be so cut and dry to your clients and there users to say 'I don't support browser X' especially if current usage is browser X. You should define the support you'd provide to that browser and it's users for the specific client.</p>
<h2 id="additional-costs" tabindex="-1">Additional Costs</h2>
<p>If you're finding yourself required to support older browsers that'll take 'a while' to get working as needed then charge accordingly. Something like a 'I support browsers X, Y and Z anything else is to be negotiated and quoted before the contract is signed and agreed upon'.</p>
<h2 id="so-you're-saying-support-ie6" tabindex="-1">So you're saying support IE6</h2>
<p>No, I'm just saying decide what browsers you are going to support and define the level of support for those devices as a base to start with and adapt for each client and their respective requirements.</p>
<h2 id="my-level-of-support%3F" tabindex="-1">My level of support?</h2>
<p>This is currently undecided, but I'd could probably say for certain that it'd be from IE8 and up, the latest Chrome/Safari/Firefox/Opera browsers on 'desktop' and then the browsers found on 'mobile devices' to be confirmed and part of me blathering on here is for me to start thinking about it. So, in January I'll hopefully know.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A responsive &quot;accordian to tabs&quot; pattern</title>
      <link href="https://www.alwaystwisted.com/articles/a-responsive-accordian-to-tabs-pattern.html"/>
      <updated>2012-10-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-responsive-accordian-to-tabs-pattern.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in August I was working for a client who 'got me on board' to deal with a variety of things one of which being the creation of some code that would turn a list of content from an accordian to some tab-ed content.</p>
<p>Along with a little help from stack overflow I managed to squeeze the workings out of jQuery and CSS so that dependant on viewport size the user would see an accordian of content or a tab navigation-ed content.</p>
<p>It worked great.</p>
<p>Some months later that man from Pittsburgh the webhead <a href="http://twitter.com/brad_frost">Brad Frost</a> created <a href="http://bradfrost.github.com/this-is-responsive/">This Is Responsive</a> a site on github containing links to resources, news and patterns around the ever growing subject of web design. I was going through this list to find that he'd included 'accordian to tab' as a pattern that hadn't been created yet.</p>
<p>I thought it'd be great to give something back to 'the community' rather than holding something like this to close to my chest. So over the last week I got to working on tidying up the code I created. I cleaned out the Samuel L. Jackson offensive quotes and replaced it with lorem ipsum and took the styling to something as simple as possible.</p>
<p>This is the result.</p>
<p>This is great for people to work from as a starting point, but there a few things that I'd like to eventually change. I'd love to get rid of dependancy on jQuery to get the show/hide to work so that it would hopefully run a little smoother on mobile as the processor won't have to work on the JavaScript framework as well. To that end I'd love to add animations to it via CSS3 rather than jQuery or JavaScript so that it's more 'progressively enhanced'. I'd also like to check the accessibility of it fully to make sure it works as well as it possibly can for as many circumstances that it could be found in.</p>
<p>I hope you like it, I hope you use it, I wish you'd break it and fix it too.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>My process is broken and that&#39;s ok.</title>
      <link href="https://www.alwaystwisted.com/articles/my-process-is-broken-and-thats-ok.html"/>
      <updated>2012-10-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/my-process-is-broken-and-thats-ok.html</id>
      <content type="html">
        <![CDATA[
        <p>It seems everyone is talking about process at the moment, whether it's broken or not. Since I've been playing with HTML, then CSS etc etc my process has adapted. From being taught in college to draw out the site map before anything else (back in 1998) everytime I've come to create a site be it designed and developed by myself or, more recently, designed by others to be coded and 'responsified' by myself I change 'bits' of how I work.</p>
<h2 id="disclaimer." tabindex="-1">Disclaimer.</h2>
<p>I can't tell you really what they are, I don't write enough things down.</p>
<p>But I'd say my process is broken, it will never be perfect. <a href="http://www.youtube.com/watch?v=HbR7axof1wk">Life moves pretty fast</a> for the chance to have a correct, 100% working process because I'm always learning and trying new things.</p>
<h2 id="always-be-changing." tabindex="-1">Always Be Changing.</h2>
<p>And, I'm happy with that. It works, it could be better, but it works, for me and clients I have work(ed) with/for. Some tools and ways or working continue project to project, possibly being refined, so slightly, each time. Things like pre-processors and how I use them have forever been in a state of flux since i first started using LESS and more recently moving to Sass/SCSS.</p>
<h2 id="adaptability." tabindex="-1">Adaptability.</h2>
<p>I can't tell you how to change your process, I can't tell the best way to do something in your process. It's your process, used by you. Who, unsuprisingly, is not me. I can suggest just the one thing.</p>
<p>Adapt.</p>
<p>After a project your next project goes out the door sit back, think of all the things that helped and all the things that hindered that project. Write them down (I'm doing this as soon as my client's client gives me things to finish). Think of what you can change, add or subtract to the process you've just gone through to make it better.</p>
<p>Client communication, design sign off, boilerplate starting files, CSS commenting, SCSS mixins, HTML/HAML templates, Photoshop editing, local enviroment development, pushing it to the server, version control and much more. There's bound to be something in your process that you can find that needs adapting, figure how you can make it better and do it, rinse and repeat.</p>
<p>Do it.</p>
<p><img src="/images/articles/benstillerdoit-ck.gif" alt="do it." loading="lazy" decoding="async"></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Content, first?</title>
      <link href="https://www.alwaystwisted.com/articles/content-first.html"/>
      <updated>2012-10-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/content-first.html</id>
      <content type="html">
        <![CDATA[
        <p>We don't need all the words in the world to start building (responsive) websites. Part of the joy of (responsive) web design is that we should have ease in responding to changes in perceived content.</p>
<h2 id="potted-paragraphs-of-history" tabindex="-1">Potted paragraphs of history</h2>
<p>In March 2005 <a href="https://twitter.com/jasonfried">Jason Freid</a> wrote a post on <a href="http://37signals.com/svn/archives/001083.php">the 37 Signals blog</a> damming 'lorem ipsum' and saying that we should '&gt;use real and relevant words not “lorem ipsum” representative text'. Then, in 2009, the <a href="http://blog.contentmanagementconnection.com/Home/20016">Content Management Connection blog</a> wrote a post that exclaimed we should be taking to create sites from the content up. Rather than painting pretty pixels with lorem ipsum we should be working with the words first before 'colouring it in'.</p>
<p>That post links back to one from 2007 by <a href="https://twitter.com/justinkistner">Justin Kistner</a> which talks about <a href="http://www.justinkistner.com/archive/content-driven-design/">Content Driven Design</a> where he talks about the box-model of the web page influencing constraints on content and helping to define it's structure. In 2008 <a href="http://twitter.com/zeldman">Jeffrey Zeldman</a> created a post on his blog with a tweet - <a href="http://www.zeldman.com/2008/05/06/content-precedes-design/">'Content precedes design. Design in the absence of content is not design, it’s decoration.'</a></p>
<p>Jump forward to 2011 and <a href="http://twitter.com/adactio">Jeremy Keith</a> in a post where he hammers <a href="http://adactio.com/journal/4523/">'home the point that it's all about the content.'</a></p>
<h2 id="content%2C-content%2C-content" tabindex="-1">Content, content, content</h2>
<p>I'm sure I've missed some parts here, but you get the point. Web design is all about the content. But what if you don't have the content? What if you're unfortunate to not have a client that can provide all the words you need before you start? Do you hold off until it's done and not eat? I think that's (obviously) ridiculous.</p>
<p>Some of us aren't fortunate enough to get every last bit of content when we get a project. Some clients just can't work like that. Some clients just won't work like that. Some clients are busy running their business and think it's your role as the web designer (which it is, if you've spec'd it in the agreed quote and project brief).</p>
<h2 id="structured-content" tabindex="-1">Structured content</h2>
<p>Recently I've been thinkin that you can still design your sites without actual content. All you'd need is the knowledge of what content there will be and then structure these 'content blocks' so they 'work' across mulitple devices.</p>
<h2 id="content-blocks" tabindex="-1">Content blocks</h2>
<p>Let's take the most used example of a blogpost and look at the 'content blocks' that it would have.</p>
<p>As you can see you could separate the heading, date, author, first paragraph, article heading, and 'the rest'. These are the content blocks that could make up a blogpost.</p>
<p>I think you can design with these content blocks and you don't neccesarily need the 'actual' content to get to work.</p>
<h2 id="but-designing-blogposts-are-easy" tabindex="-1">But designing blogposts are easy</h2>
<p>Ok, so let's talk about something else. How about a product page for ecommerce site that sells kettles? For this we're only going to focus on the the actual product bits, not the header, navigation or footer.</p>
<p>So first off, we would have a 'the product title'. Then maybe, as it's for an ecommerce site you'd have a price, a brief list of product details, a call-to-action 'buy' button, some social buttons so users can tell their friends they're buying it, a bigger description of the product, a more thorugh list of product details, a product code, a print button and so forth.</p>
<p>So you could start designing the layout and the paint of the page knowing what content blocks are neede and not neccesarily knowing the content.</p>
<h2 id="a-consideration" tabindex="-1">A consideration</h2>
<p>To do something like this would need a change in process. You'd need reiteration on the content blocks over the time of design and development of the site/app. With responsive web design this is now (in my opinion) easier than ever as you should be in a statle of 'agile' development.</p>
<p>Of course, this works for me but it could mean it's likely that it might not work for you. You may have all the content first, you might work on your own stuff and not need the content as 'you know' what it'll be.</p>
<h2 id="still-get-your-content-as-soon-as-possible" tabindex="-1">Still get your content as soon as possible</h2>
<p>I'm not writing this to convince that 'content first' shouldn't be taken as seriously as people have written or spoken about. It is. But if you're waiting on it you can get some work done in the mean time, but still strive to get the content as soon as is possible into your work.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>These 3 lines</title>
      <link href="https://www.alwaystwisted.com/articles/these-3-lines.html"/>
      <updated>2012-10-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/these-3-lines.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in March, that Andy Clarke wrote a post on the need for a <a href="http://stuffandnonsense.co.uk/blog/about/we_need_a_standard_show_navigation_icon_for_responsive_web_design">'standard' icon for navigation</a> in responsive web design. Two month's later in May, when I found my blogging 'mojo', I wrote a post on making <a href="../post.php%EF%B9%96s=2012-05-12-create-a-pure-css-menu-button.html">navigation icons with only CSS</a>. Then some months later Jeremy Keith wrote an article on three lined <a href="http://adactio.com/journal/5666/">'navicons'</a> and two days later Tim Kadlec took a similar approach to mine and created a <a href="http://timkadlec.com/2012/08/mobile-navigation-icons/">better CSS version</a> of the three lines icon using nice and responsive ems.</p>
<p>This week Jordan Moore (not the country singer) wrote a post on '<a href="http://mobile.smashingmagazine.com/2012/10/08/the-semantic-responsive-design-navicon/">The semantic, Responsive Navicon</a>' and a couple of days later the trickster Chris Coyier wrote a post that showed various ways to have the <a href="http://css-tricks.com/three-line-menu-navicon/">three lines as a responsive navicon</a>.</p>
<p>After Jordan's post, there was a brief <a href="https://twitter.com/brad_frost/status/255293924472680448">discussion on twitter</a> on the use of the icon and 'it depends'. So I thought I'd quickly throw down some thoughts on what I think.</p>
<p>So, here goes.</p>
<h2 id="icon" tabindex="-1">Icon</h2>
<p>I think the icon is great, I think the fact that a site that has <a href="http://www.bbc.co.uk/news/technology-19816709">over a billion users</a> of which just under <a href="http://www.socialbakers.com/blog/554-facebook-hits-488-million-mobile-users-infographic">half access via mobile</a> which (possibly not for all devices) uses the icon helps. A lot. Yes, Facebook's site is more 'app-like' than your common or garden, um, garden centre website but I'm sure (at a wild guess) those users will recoginise it on the website you've created for your client.</p>
<h2 id="words" tabindex="-1">Words</h2>
<p>I also think that if you've decided to go with the three lines including the word 'menu' is just a little bit of extra bulk you don't need. Let's not forget that space on a narrow viewport is at a premium, you could be taking up precious white space by 're-affirming' what the icon is doing. So I would suggest one or the other. Not both. As well as my feeling towards the added 'bulk' it's not very all encompassing in the World Wide Web.</p>
<h2 id="for-instance..." tabindex="-1">For instance...</h2>
<p>menu is four charecters, in Icelandic the word is Valmynd. That's three extra charecters taking up room, breaking your site, making it look crappy.</p>
<h2 id="opinion" tabindex="-1">Opinion</h2>
<p>Of course, this is just my opinion. There are many opinions like it, but this one is mine. If I was to use an icon for navigation on a narrow viewport I would use three lines with no wording.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Coda 2 wish list</title>
      <link href="https://www.alwaystwisted.com/articles/a-coda-2-wish-list.html"/>
      <updated>2012-09-17T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-coda-2-wish-list.html</id>
      <content type="html">
        <![CDATA[
        <p>So, if you've been following along my twitter account you would have seen I've started to use Coda 2 as my main code editor for all the fun HTML, CSS and JavaScript I get to do. I started using Coda when I got my first Mac in 2009 after years of using Dreamweaver (ever since version 3). I had a dalliance with Espresso 2 for 6 months and wasn't to keen on what I saw of Coda 2.</p>
<p>Then I decided to try it for a client project. To see how I go along.</p>
<p>Since using it daily for quite a while now I've, every now and then, found some things that'd I really like to be added to the upcoming updates which I think will make such a great product even better.</p>
<p>This list is in absolutely no particular order and I may add to this post as and when I ever think of them.</p>
<h2 id="a-project-todo-list" tabindex="-1">A project todo list</h2>
<p>You've got your current project open. Maybe there's the HTML and CSS page open. You think of something that you need to add on a todo list for the project. Wouldn't it be great if you can do that somewhere within Coda? You could have it as an option in the sidebar. Having the todos for a project tied to the project rather than a third party would, I feel, speed up your work and aid your concentration. Rather than flitting from Coda to a todo app to Coda again.</p>
<h2 id="the-sidebar-open%2Fclosed-per-file." tabindex="-1">The sidebar open/closed per file.</h2>
<p>Currently I'm finding I use the sidebar when I'm editing the CSS but don't want it there when I'm playing my HTML. It'd be great if, somehow, The sidebar would remember it's open or closed state on a per file basis rather than per project. I'm sure if I still and my 27' iMac instead of this 13' MBA I'd have The sidebar open all them time though. But it'd be a great option.</p>
<h2 id="add-markdown-files-as-a-book." tabindex="-1">Add Markdown files as a book.</h2>
<p>When I'm writing my CSS with LESS I'm more often than not using Clearleft's ClearLESS LESS library made by // All Marked Up //. This library has a fantastic markdown file of all the what's and wherefores to help and it'd be great if I could have this nicely accessible in say the Books format in Coda. So I can have it open and easily readable.</p>
<h2 id="add-a-viewport-dimensions-helper-to-the-preview" tabindex="-1">Add a viewport dimensions helper to the Preview</h2>
<p>Although, yes, I do 'design in the browser' and test on a variety of devices I find myself using the preview in Coda quite a lot for initial layout and colouring in. Sometimes I use the built-in iOS 'user agents' but when I don't it's because I'm resizing the 'browser'. It'd be great to have an option to include a live dimensions of the viewport. Like Dave Rupert's fantastic FitWierd.</p>
<h2 id="a-key-and-mouse-shortcut-for-'jump-to-style'" tabindex="-1">A key and mouse shortcut for 'Jump to Style'</h2>
<p>Still using Preview, I really like the idea of being able to go to the line of CSS for a particular element from looking at the rendered page. Rather than (or as well as) having it as a right-click menu option I'm sure it'd speed up development if it was (also) a mouse(trackpad) and keyboard shortcut. Something like shift + cmd + click so that I can quickly get to CSS code. Of course this could prove tricky as some elements have more than one class etc but maybe the mouse/key shortcut could open up the options of CSS available. I'm sure that'd be a little quicker than right-click, move the mouse down, across and select.</p>
<h2 id="jump-to-style-goes-to-open-less%2Fsass-file" tabindex="-1">Jump to Style goes to open LESS/Sass file</h2>
<p>As I've mentioned in wish number 3. I use LESS, I also use Sass (well the SCSS syntax). If in my project I've got a Sass or LESS file open I'd love the Previews 'Jump to Style' to be able to go to those files rather than my compressed one line of CSS which I can't read.</p>
<h2 id="only-view-certain-types-in-the-navigator" tabindex="-1">Only view certain types in The Navigator</h2>
<p>Sometimes I add bookmarks to my CSS so I can jump to them quickly. It'd be really good if, in The Navigator, I could just view the bookmarks for the file that's open rather than all the CSS classes (for example) as well. You can arrange all the bits that Navigator by kind or Name. I'd really love to be able to only see certain types (like bookmarks).</p>
<h2 id="move-the-'iphone'-about" tabindex="-1">Move the 'iPhone' about</h2>
<p>When I'm using the Preview mode I sometimes have the iPhone 'user agent' set. It'd be really nice if I click to inspect element I could move the 'iPhone' so that I can easily view the webkit inspector (granted this would not be an issue on a 27' iMac).</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Slightly Bizarre goings-on #1</title>
      <link href="https://www.alwaystwisted.com/articles/slightly-bizarre-goings-on-1.html"/>
      <updated>2012-09-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/slightly-bizarre-goings-on-1.html</id>
      <content type="html">
        <![CDATA[
        <p>If you've <a href="http://twitter.com/sturobson">followed me on twitter</a> over the last couple of days, you may have seen some mad panic as I managed to b0rk this sites <a href="http://grabaperch.com/">Perch CMS</a> installation. I managed to roll back to v1 of the CMS last night and have been itching to write a post since.</p>
<p>Having recently read <a href="http://css-tricks.com/chronicle-i/">Chris Coyiers</a> post and just moments ago see that <a href="http://pauladamdavis.com/blog/2012/09/memoirs-of-a-coder-1/">Paul Adam Davis</a> has started a 'weekly update' kind of post too. I thought it was a great idea. Hopefully this'll help you and me. I'll be adding great things I find (which hopefully'll help you) and just bumbing on about how my week has been (which may aid my faultering memory).</p>
<h2 id="slightly-bizarre-%3F" tabindex="-1">Slightly Bizarre ?</h2>
<p>When I was in 'a rock band' our first gig got a review in a local weekly magazine. The words 'Always twisted, slightly bizarre' were used when referring to my guitar riffs. Those four words have stuck with me since then (2002). I've finally found a home for 'slightly bizarre'</p>
<h2 id="what's-been-going-on." tabindex="-1">What's been going on.</h2>
<ol>
<li>I'm still writing my 8/9/10+ part series on resposnive web design for WebTutsPlus. I'm hoping to have the first two articles out the door in the next week or two.</li>
<li>I'm currently working on the smallest, biggest client site ever.</li>
<li>I've splurged some cash on <a href="http://2013.newadventuresconf.com/">New Adventures</a>, <a href="http://2012.webdevconf.com/">Web Developers Conference</a> and <a href="http://www.handheldconf.com">Handheld</a> conference tickets.</li>
<li>I've been playing with <a href="http://jsfiddle.net/sturobson/jrTcg/">a little accordian &gt; tabs bit of code</a> for a clients site which I want to improve.</li>
<li>This blog has loads of drafts that need completing, when I have the time.</li>
<li>I'm about 40% at my 'go freelance' savings.</li>
</ol>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Sass mixin for media queries and IE</title>
      <link href="https://www.alwaystwisted.com/articles/a-sass-mixin-for-media-queries-and-ie.html"/>
      <updated>2012-08-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-sass-mixin-for-media-queries-and-ie.html</id>
      <content type="html">
        <![CDATA[
        <p>I'm currently finishing up some front-end co-coding for a client who hired me for all the mobile/responsive goodness. As well as this they wanted me to instigate and create the CSS using Sass/SCSS. Near the end of the project they asked how we would support IE8/7/6.</p>
<p>We did discuss this at the start of the project but carried on with 'all the things'. I had seen all the hotness around <a href="http://thesassway.com/intermediate/responsive-web-design-in-sass-using-media-queries-in-sass-32">Sass 3.2</a> that would allow you to create a <a href="https://gist.github.com/1493930#file_style.scss">respond-to mixin</a>. So decided to upgrade my Sass gem to the <a href="http://rubygems.org/gems/sass/versions/3.2.0.alpha.278">latest version</a> and updated all my 'hand coded' media queries with the relevant Sass/SCSS mixins.</p>
<p>This was great, kinda, it now took the px/em value out of the CSS and allowed me to change it in my Sass settings/mxins/variables file but it did not let me create a fallback for internet explorer.</p>
<p>Here is the SCSS and the CSS I wanted/expected.</p>
<h3 id="the-scss-setup" tabindex="-1">The SCSS setup</h3>
<p>// Setting up a quick respond-to mixin
@mixin respond-to($name) {
@if $name == tablet {
@media only screen and (min-width: 768px) { @content; }
}
}</p>
<p>// So this is the mixin that I'm currently using</p>
<p>@mixin this-is-what-i-want($name. $ie-class) {
ie-class-here { @content; }
media-query-here } @content; }
}</p>
<h3 id="the-scss-file" tabindex="-1">The SCSS file</h3>
<p>// This is how I include the mixin within my SCSS file</p>
<p>.foo {
margin: 0 auto;
padding: 0 10px;§</p>
<p>@include this-is-what-i-want(tablet, lt-ie9) {
min-width: 940px;
max-width: 1220px;
padding: 0 20px;
}
}</p>
<h3 id="my-'wished-for'-css-output" tabindex="-1">My 'wished for' CSS output</h3>
<p>.foo {
margin: 0 auto;
padding: 0 10px;§
}</p>
<p>.lt-ie9 .foo {
min-width: 940px;
max-width: 1220px;
padding: 0 20px;
}</p>
<p>@media only screen and (min-width: 768px) {
.foo {
min-width: 940px;
max-width: 1220px;
padding: 0 20px;
}
}</p>
<h3 id="to-the-internets" tabindex="-1">To The Internets</h3>
<p>So I started crawling the <a href="http://gist.github.com/">gists on gitub</a> to see if anyone had created a little code snippet just for this reason. I didn't. There was nothing. So I quickly asked some really, clever and amazing people on the twitters and I got this bit of code from the fantastic <a href="http://twitter.com/snugug">@snugug</a>.</p>
<p>mixin respond-wrapper-fallback($name, $wrapper-class) {
.#{$wrapper-class} &amp; {
@content;
}
@include respond-to($name) {
@content;
}
}</p>
<p>This now turns my 'wished for' CSS output into a reality and now means I can create a fallback for Internet Explorer from 'whatever' CSS Media Query block I need.</p>
<h2 id="to-skin-a-cat." tabindex="-1">To skin a cat.</h2>
<p>There's more than one solution for patching up code for Internet Explorer using Sass. This is the solution I required. <a href="https://en.twitter.com/jaffathecake">Jake Archibald</a> created a <a href="http://jakearchibald.github.com/sass-ie/">IE-friendly mobile-first solution</a> which I shall be likely to use at the start of future projects and there's <a href="http://nicolasgallagher.com/mobile-first-css-sass-and-ie/">Nicolas' solution</a> also.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Books For Sale</title>
      <link href="https://www.alwaystwisted.com/articles/books-for-sale.html"/>
      <updated>2012-08-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/books-for-sale.html</id>
      <content type="html">
        <![CDATA[
        <p>Ok, I'm selling these books. The prices are a guide and they include P&amp;P.</p>
<p>If you want to buy any of these, <a href="http://twitter.com/sturobson">let me know via twitter</a> or via email - <a href="mailto:stu@alwaystwisted.com?subject=books%20for%20sale...">stu@alwaystwisted.com</a></p>
<p>Payment is expected to be completed via bank transfer (paypal is a last resort though).</p>
<p>A Practical Guide to Information Architecture - £20</p>
<p>A Practical Guide to Designing with Data - £20</p>
<p>The Mobile Frontier - £20</p>
<p>Writing For The Web - £8</p>
<p>HTML5 and CSS in the real world - £15</p>
<h2 id="the-original-list" tabindex="-1">The original list</h2>
<p>CSS Mastery (2nd edition) - £8</p>
<p>Bulletproof Web Design (2nd edition) - £6</p>
<p>CSS The Missing Manual - £7</p>
<p>practical information article - £6</p>
<p>Content Strategy for the web (1st edition) - £9</p>
<p>Beginning iPhone 3 development - £7</p>
<p>Everything you know about CSS is wrong! - £7</p>
<p>Principles of beautiful web design (1st edition) - £7</p>
<p>Sexy Web Design - £8</p>
<p>PHP, MySQL and Apache All in One - £12</p>
<p>Accelerated DOM Scripting with Ajax, APIs and Libraries - £6</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Just a little cog...</title>
      <link href="https://www.alwaystwisted.com/articles/just-a-little-cog.html"/>
      <updated>2012-07-22T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/just-a-little-cog.html</id>
      <content type="html">
        <![CDATA[
        <p>If you've been following me on the twitters recently you may have seen the odd tweet about me 'getting ready' for the world of full time freelance front-end development. I'm currently only 'coding by candlelight' in the evenings whilst holding down a day job (which is completely the opposite to anything which involves a computer).</p>
<p>I've slowly started getting some work, good work. I'm saving what I can. You see, working 9-5 and being a family man whilst trying to carve out a freelance career in web design/development means my hourly working week as a night-owl is quite small. Although I do my best, catching five minutes here and there as well as evening shifts of up to 4 hours I can pull in about a 20 hour week. But I'm digressing about the point of this post.</p>
<h2 id="i'm-not-jack." tabindex="-1">I'm not Jack.</h2>
<p>When I started 'playing' with the web it was all tables and spacer.gifs. Fun days, 'easy' days. Now we've got all these little niches within the industry I don't think we really classified back then. I was a 'web designer' (not a site manager) I'm now a 'front-end developer'. I try and concentrate my efforts on HTML, CSS and JavaScript. I can't really design for toffee but I love getting my hands filthy with code. I don't know much about PHP. I'm not a Jack of all trades but an attempted master of 3.</p>
<h2 id="but-it's-not-that-easy." tabindex="-1">But it's not that easy.</h2>
<p>Although I concentrate on what I like to refer to as creating the 'code that makes the page you use' there's more to it now than just 'holy trinity' of HTML, CSS and JavaScript. Trying to be a little cog, a cog that'd fit perfectly into your project I try to adapt. I'm not made out of steel iron, I'm malleable.</p>
<p>I'm starting to think that really, you have got to be 'adaptable'. I'm currently working for a client that uses Sass (well SCSS) which I tried around Christmas last year <a href="https://twitter.com/sturobson/status/118756553166823424">but</a> I ended up going straight to LESS as, for me, it worked out of the box. So <a href="http://alwaystwisted.com/post.php?s=2012-07-08-stu-goes-sass">I'm learning Sass/SCSS</a> not only to work with this client but to make myself more knowledgeable and adaptable for future clients. If I know <a href="http://www.youtube.com/watch?v=tScm-eZInBE">this, that and the other</a> I'll be a better fit for a client and I want to be a better (if not perfect) fit, surely that'd get me work, right?</p>
<h2 id="%23teamweb" tabindex="-1">#teamweb</h2>
<p>So as part of being this little cog I get fed up. It shouldn't be about winning and losing at something such as pre-processors. For me, wanting to 'find my feet' (and more work) I think you should know as much as you can possibly fit in your head. Don't stick with what's the most popular, easiest to implement. Try everything once (well not everything *coughs*), if at first you don't succeed, try, try, try again. Learning what you can and as much of it as you can would make you a more rounded front-end developer able to pick up something you have a hand on and make beautiful.</p>
<p>You may think from my recent tweets that I'm edging to #teamsass but the redesign of this site will be using LESS. I gotta keep the cog whirring, playing with stuff, learning, adapting, creating awesomeness.</p>
<h2 id="back-to-the-future!" tabindex="-1">Back to the future!</h2>
<p>So I apologise for a little rambling, but I just needed to get this down. I'm looking forward to and hoping to make 'the leap' soon and I think being able to 'adapt' to my clients needs as a front-end developer is important. So if you're looking for a malleable front-end developer in the next few months, <a href="mailto:stu@alwaystwisted.com?subject=A%20maleable%20request">hit me up</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A case for some Accessibility in our CSS</title>
      <link href="https://www.alwaystwisted.com/articles/a-case-for-some-accessibility-in-our-css.html"/>
      <updated>2012-07-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-case-for-some-accessibility-in-our-css.html</id>
      <content type="html">
        <![CDATA[
        <p>On Tuesday, <a href="http://twitter.com/johnfoliot">John Foliot</a> posted a little question on twitter.</p>
<blockquote>
<p>Question: why *CAN'T* we add ARIA directly to CSS? I haz use-cases | @<a href="https://twitter.com/glazou">glazou</a> @<a href="https://twitter.com/mollydotcom">mollydotcom</a> @<a href="https://twitter.com/fantasai">fantasai</a> @<a href="https://twitter.com/tabatkins">tabatkins</a></p>
<p>— John Foliot (@johnfoliot) <a href="https://twitter.com/johnfoliot/status/225275558328664064">July 17, 2012</a></p>
</blockquote>
<p>At first I thought this would be a bit crappy, adding accessibility to CSS which is for presentation sounded like a horrendous idea. Myself, <a href="http://twitter.com/johnfoliot">John</a>, <a href="http://twitter.com/mollydotcom">Molly</a> and <a href="http://twitter.com.inkpixelspaper">Jen</a> discussed this on the twitters a little further and I was still left not convinced. It seemed a horrible hack to try and get lazy assed developers to include aria roles to their sites. As I pointed out, if <a href="http://alwaystwisted.com/post.php?s=2012-06-01-your-website-stinks-on-mobile">developers are lazy enough</a> to not include all the <a href="http://alwaystwisted.com/post.php?s=2012-05-03-the-horse-has-bolted-oreally">relevant prefixes</a>, they'd probably not include this either (which is quite sad, really).</p>
<p>There was discussion that CSS is for presentation only, but i think with the onset of CSS3 animation whizz-bangs etc. we can adapt.</p>
<h2 id="roll-on-a-few-days." tabindex="-1">Roll on a few days.</h2>
<p>I'm currently sub-contracted by a client for some front-end development and consultancy on a site that's got a huge mega-nav, dropdown, suckerfish wotsit. It's huge, really huge and, of course, I wanted to make it accessible as possible. So I've added the relevant aria roles <a href="http://www.w3.org/TR/wai-aria/roles#menu">menu</a>, <a href="http://www.w3.org/TR/wai-aria/roles#menubar">menubar</a> and <a href="http://www.w3.org/TR/wai-aria/roles#menuitem">menuitem</a>. There were a lot of menu-items it got boring, very boring. I did use find and replace to help, luckily. So I was warming to John's idea around his question.</p>
<h2 id="how-can-it-be-done%3F" tabindex="-1">How can it be done?</h2>
<p>I tweeted that I was warming to it and struck up another quick conversation with John. He said that a colleague had suggested using attr as a CSS declaration. I think this makes perfect sense. So, for example, we've got a menu with 7 main menu links of which these have sub-menus containing 30 links. So that'd be 38 aria roles that need adding to your HTML.</p>
<h3 id="an-aside..." tabindex="-1">An aside...</h3>
<p>Adding all of that, those 38 aria roles to your HTML can make it look a little pale. Although correct, it'd even be cleaner if it was in the CSS. But I digress.</p>
<h2 id="in-the-css." tabindex="-1">In the CSS.</h2>
<p>So back to the CSS. To add the aria roles to the page now we could just write 3 lines of code within the CSS rather than 37 bits of code sprinkled around HTML.</p>
<p>nav { attr: menu; }
nav ul { attr: menubar; }
nav li { attr: menuitem; }</p>
<p>It's pretty easy isn't it? It's actually quite clean too. We could even use that for footer navigation too. This way our markup is lean, our CSS is snazzy and we're doing our best for accessibility, which is no bad thing.</p>
<h2 id="what-now%3F" tabindex="-1">What now?</h2>
<p>I don't really know, I guess someone (me?) needs to write this all up nicely and put it to the <a href="http://www.w3.org/blog/CSS/">CSS working group</a>. I haven't (currently) the time for this but hopefully I can make a start.</p>
<h2 id="what-about-you%3F" tabindex="-1">What about you?</h2>
<p>What do you think? Bad idea? Good idea? A problem that doesn't need solving?</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Stu goes Sass...</title>
      <link href="https://www.alwaystwisted.com/articles/stu-goes-sass.html"/>
      <updated>2012-07-08T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/stu-goes-sass.html</id>
      <content type="html">
        <![CDATA[
        <p>If you follow me on the twitters (and you should <a href="http://twitter.com/sturobson">follow me on the twitters</a>) you'll have know doubt seen that this last week or so I've been getting my head around Sass.</p>
<h2 id="disclaimer%3A" tabindex="-1">Disclaimer:</h2>
<p>I know I've written for my love for LESS on here <a href="http://alwaystwisted.com/post.php?s=2012-06-05-another-approach-to-mobile-first-css-whilst-supporting-internet-explorer">many</a>, <a href="http://alwaystwisted.com/post.php?s=2012-05-28-how-im-rolling-my-media-queries">many</a>, <a href="http://alwaystwisted.com/post.php?s=2012-05-17-content-choreography-mixins-in-less">many</a>, <a href="http://alwaystwisted.com/post.php?s=2012-05-05-everyday-im-bubbling-with-media-queries-and-less">many</a> <a href="http://alwaystwisted.com/post.php?s=2011-12-01-a-less-approach-to-mobile-first-css-supporting-older-ie-browsers">times</a>. I've still got the love for LESS but my current client requires Sass/SCSS so I've been learning that as quick as possible (note: if you know LESS it's not that difficult).</p>
<h2 id="loads-of-resources." tabindex="-1">Loads of resources.</h2>
<p>So basically this is a blogpost of all the resources I've been reading, re-reading and learning from to get my Sass/SCSS chops down. So here goes, in no order whatsoever.</p>
<p>A really good <a href="https://speakerdeck.com/u/imathis/p/sass-compass-the-future-of-stylesheets-now">Sass &amp; Compass slidedeck</a> from <a href="https://twitter.com/imathis">Brandon Mathis</a>.</p>
<p>A <a href="http://www.jc-designs.net/pdf/sassCheat.pdf">Sass/SCSS/Compass cheatsheet</a> pdf file to print off and stick on your MBA.</p>
<p>What's <a href="http://thesassway.com/intermediate/responsive-web-design-in-sass-using-media-queries-in-sass-32">coming in Sass 3.2</a> in regards to the coolness of media queries.</p>
<p><a href="http://susy.oddbird.net/">Susy</a>, a responsive grid system for/using Compass.</p>
<p>A front-end starter kit called <a href="https://github.com/tokokoo/pondasee">Pondasee</a>.</p>
<p>Another slidedeck - <a href="http://www.slideshare.net/BeritJensen/save-time-by-using-sassscss">save time by using Sass/SCSS</a>.</p>
<p>A blogpost on <a href="http://railslove.com/blog/2012/03/28/smacss-and-sass-the-future-of-stylesheets/">SMACSS and Sass</a>.</p>
<p><a href="http://compass-style.org/">Compass</a>, an open source framework for Sass.</p>
<p>A blogpost on calculating <a href="http://erskinelabs.com/calculating-ems-scss/">EMs with SCSS</a>.</p>
<p><a href="http://viget.com/inspire/sass-a-designers-perspective">Sass from a designers perspective</a> (blogpost).</p>
<p>A bunch of <a href="http://www.youtube.com/playlist?list=PL2CB1F80266E986EA&amp;feature=plcp">Sass tutorials on YouTube</a>.</p>
<p>I'm using the <a href="http://compass.handlino.com/">Compass.app</a> it's only 10 bucks!</p>
<p><a href="http://www.slideshare.net/adarowski/sassive-aggressive-level-up-your-css-with-sass">Sassive Agressive</a>, another slidedeck.</p>
<p><a href="http://sass-lang.com/">The Sass website</a>.</p>
<p><a href="https://github.com/thoughtbot/bourbon">Bourbon</a> (it's like Compass).</p>
<p><a href="http://css-tricks.com/sass-vs-less/">Sass vs. LESS</a> and <a href="http://css-tricks.com/video-screencasts/88-intro-to-compass-sass/">an intro to Sass/COMPASS</a> from <a href="http://twitter.com/chriscoyier">Chris Coyier</a>.</p>
<p>Part 1 of <a href="http://net.tutsplus.com/tutorials/other/mastering-sass-lesson-1/">Mastering Sass</a> from nettuts+.</p>
<p>The <a href="https://twitter.com/thesassway">@thesassway</a> twitter account.</p>
<p><a href="https://github.com/Snugug/Aura">Aura</a>, a responsive Sass and Compass framework from <a href="http://twitter.com/sungug">@sungug</a>.</p>
<p>Another framework, <a href="http://thecodingdesigner.com/">The coding designer</a></p>
<h2 id="finally." tabindex="-1">Finally.</h2>
<p>To top things off if, in the words of Bill Hicks, you're a reader there's a fantastic book to take you from the start - <a href="http://pragprog.com/book/pg_sass/pragmatic-guide-to-sass">The Pragmatic Guide To Sass</a> - available in all good retailers I'm sure.</p>
<h2 id="one-more-thing." tabindex="-1">One More Thing.</h2>
<p>I'm sure I've missed your post, video, twitter account. If you've got some fantastic Sass/SCSS/Compass resource I've missed out on then please do add a comment to this post. Let's get a big resource going.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Rejuvenate your inbox with some web development newsletters</title>
      <link href="https://www.alwaystwisted.com/articles/rejuvenate-your-inbox-with-some-web-development-newsletters.html"/>
      <updated>2012-06-23T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/rejuvenate-your-inbox-with-some-web-development-newsletters.html</id>
      <content type="html">
        <![CDATA[
        <p>Daily we can get access to new and fantastic news, techniques, processes for our jobs. Sometimes we miss things. Sometimes we're too busy doing the actual 'work' part of our jobs to keep up with current 'trends' and these new new things.</p>
<p>So why not sign up to some email newsletters? Get yourselves a lovely weekly digest straight in your inbox. Read it at your desk, on the commute, even in the loo. Letting someone else collate the news and give you a nice 'précis' is a perfect way to keep your head above water.</p>
<p>Here are a few I sign up to.</p>
<p><a href="http://web-design-weekly.com/">Web Design Weekly</a></p>
<p>Giving you some news, techniques, tutorials and inspirational pieces weekly.</p>
<p><a href="http://css-weekly.com/">CSS Weekly</a></p>
<p>Some select articels all about what's being created and said about CSS and CSS3.</p>
<p><a href="http://html5weekly.com/">HTML5 Weekly</a></p>
<p>All things HTML5, not just the markup. News, articles, tools, videos, demos and more.</p>
<p><a href="http://www.webdeveloperweekly.com/">Web Developer Weekly</a></p>
<p>An email of 'all things' web developer.</p>
<p><a href="http://responsivedesignweekly.com/">Responsive Design Weekly</a></p>
<p>Some fantastically collated news, tutorials, presentations, tools and resources all about responsive web design.</p>
<p><a href="http://bradfrostweb.com/responsive-web-design-newsletter/">Responsive Web Design Newsletter</a></p>
<p>Another equally fantastic collation of information for all things responsive from that handsome chap <a href="http://twitter.com/brad_frost">Brad Frost</a>.</p>
<h3 id="updates" tabindex="-1">Updates</h3>
<p>Just after throwing this post up on the twitters that fancyman of Croydon <a href="http://twitter.com/mrqwest">MrQwest</a> suggested adding <a href="http://javascriptweekly.com/">Javascript Weekly</a> to the list. Whilst lookin at it and signing up I then found out about <a href="http://rubyweekly.com/">Ruby Weeky</a> too.</p>
<p>So are there any more out there? Please add them to the comments.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>We&#39;re all reading the same book, but we&#39;re all on different pages.</title>
      <link href="https://www.alwaystwisted.com/articles/were-all-reading-the-same-book-but-were-all-on-different-pages.html"/>
      <updated>2012-06-20T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/were-all-reading-the-same-book-but-were-all-on-different-pages.html</id>
      <content type="html">
        <![CDATA[
        <p>There has been quite a few blogposts from different online magazines recently that has been given a bit of a backlash on the twitters. Some of these posts have been considered incorrect, factually biased or just 'plain wrong'. Some have been questioned as to why such a 'well known' topic needs rewriting today where they one from a couple of years ago works just fine.</p>
<h2 id="it's-pretty-simple..." tabindex="-1">It's pretty simple...</h2>
<p>Think of the web industry and your career as a book. We're all reading the same book but some of us are faster readers than others. Some of us misread chapter three and four. Some of us have skipped a couple of chapters to get to the juicy bits. Some of us are only starting on chapter one, page one today.</p>
<p>If we think of this industry along with our careers like this, it's easier to understand why such a post has been written. Whether completely incorrect or just a repeat of what you already know.</p>
<h2 id="be-excellent-to-each-other..." tabindex="-1">Be excellent to each other...</h2>
<p>If the post you read is completely incorrect, factually wrong and full of horse shit. Don't slate the writer because let's face it they're probably a few chapters behind you. Be <a href="https://www.youtube.com/watch?v=3bTvDKcxZuY">excellent to each other</a>. Offer your criticisms a polite way (a direct email, a comment on the post). Be civil. Calling stuff out to your twitter followers as horse shit (or similar) does yourself, them and the world no favours. Stop that.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Another approach to mobile first CSS whilst supporting Internet Explorer</title>
      <link href="https://www.alwaystwisted.com/articles/another-approach-to-mobile-first-css-whilst-supporting-internet-explorer.html"/>
      <updated>2012-06-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/another-approach-to-mobile-first-css-whilst-supporting-internet-explorer.html</id>
      <content type="html">
        <![CDATA[
        <p>Back in December I wrote a blogpost on <a href="http://alwaystwisted.com/post.php?s=2011-12-01-a-less-approach-to-mobile-first-css-supporting-older-ie-browsers">a LESS approach for mobile first CSS &amp; supporting older IE browsers</a> where I described the current ways (at the time) of creating a IE specific stylesheet from several seperate files. I also described how I thought it should work and since the launch of LESS.js version 1.2.0 it's easier than ever to do.</p>
<p>Roll on 6 months and I have changed how <a href="http://alwaystwisted.com/post.php?s=2012-05-28-how-im-rolling-my-media-queries">I intend to write my LESS</a> using <a href="http://alwaystwisted.com/post.php?s=2012-05-05-everyday-im-bubbling-with-media-queries-and-less">media query bubbling</a> that keep the media queries within the element which I find easier when editing. Which looks like this.</p>
<p>header {
background-color: red;
@media screen only and (min-width: 20em) {
background-color: blue;
}
}</p>
<p>An overhead I've still yet to test is performance but I still hazard a guess that it'd be negligible.</p>
<h2 id="a-back-story." tabindex="-1">A back story.</h2>
<p>Last Wednesday (May 30th 2012) <a href="http://twitter.com/boagworld">Paul Boag</a> wrote a post <a href="http://boagworld.com/tumblog/putting-media-queries-in-their-place/">exclaiming his wishes</a> for LESS which media query pretty much caters for. After a quick firing of tweets Paul also wanted to support those browsers (IE 7 &amp; 8) that don't support CSS3 media queries.</p>
<p>I mentioned that he could use the original technique I blogged about, but this wouldn't allow him to use bubbling. I also mentioned he could 'do a cron job' to strip out the media query rules that <a href="http://twitter.com/richquick">Rich Quick</a> mentioned at the <a href="http://port80events.co.uk/">Port 80</a> conference earlier in May (<a href="http://www.slideshare.net/richardfquick/rwd-in-the-wild">slides</a>).</p>
<h2 id="a-workable-solution." tabindex="-1">A Workable Solution.</h2>
<p>After much head scratching I found a way to create some internet explorer specific styles within your LESS files whilst still using media query bubbling.</p>
<p>First off we need to 'borrow' the <a href="http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/">HTML conditional classes</a> that are used within the <a href="http://html5boilerplate.com/">HTML5 boilerplate</a>. I say borrow as personally I don't take the code verbatim and have stripped out bits, changed little things so it works more for me as I code differently to you as you do to me.</p>
<p>This is the HTML code we need</p>
<!--\[if lt IE 7\]> <html class='no-js lt-ie9 lt-ie8 lt-ie7' lang='en'> <!\[endif\]-->
<!--\[if IE 7\]>    <html class='no-js lt-ie9 lt-ie8' lang='en'> <!\[endif\]-->
<!--\[if IE 8\]>    <html class='no-js lt-ie9' lang='en'> <!\[endif\]-->
<!--\[if gt IE 8\]><!--> <html class='no-js' lang='en'> <!--<!\[endif\]-->
<p>Now we've got that at the top of our HTML page straight after the doctype declaration we're good to go with diving into our LESS file.</p>
<p>As I mentioned above I've started writing my LESS like this.</p>
<p>header {
background-color: red;
@media screen only and (min-width: 20em) {
background-color: blue;
}
}</p>
<p>Which when compiled into CSS returns us with this.</p>
<p>header {
background-color: red;
}</p>
<p>@media screen only and (min-width: 20em) {
header {
background-color: blue;
}
}</p>
<p>Here we have our mobile first or 'base' CSS style to the element (in this case the background colour of the header will be red for devices and browsers that don't support media queries). What we could now do is add some code to the LESS file that'll give the <header> a IE specific class. This is achieved by writing something like this</p>
<p>~.lt-ie8&amp;&amp;&amp; { background-color: green; }~</p>
<p>.lt-ie8&amp; { background-color: green; }</p>
<p>This uses ~&amp;&amp;&amp;~ &amp; which takes the preceding element and then puts the .lt-ie8 class in front of it. So for example writing this LESS.</p>
<p>header {
background-color: red;</p>
<p>~.lt-ie8&amp;&amp;&amp; {
background-color: blue;
}~</p>
<p>.lt-ie8&amp; {
background-color: blue;
}</p>
<p>}</p>
<p>Gives us this CSS.</p>
<p>header {
background-color: red;
}
.lt-ie8 header{
background-color: blue;
}</p>
<p>As you can see we're half way there to media query bubbling anyway so by doing this.</p>
<p>header {
background-color: red;</p>
<p>~.lt-ie8&amp;&amp;&amp; {
background-color: blue;
}~
.lt-ie8&amp;&amp;&amp; {</p>
<p>background-color: blue;
}</p>
<p>@media screen only and (min-width: 20em) { background-color: green; } }</p>
<p>We would then, when compiled, get this CSS.</p>
<p>header {
background-color: red;
}</p>
<p>.lt-ie8 header {
background-color: blue;
}</p>
<p>@media screen only and (min-width: 20em) {
header {
background-color: green;
}
}</p>
<p>This way we can then have our mobile first (or base) style, followed by class specific styles for whichever browsers you are supporting on your project and then all the fun of the fair in the media queries.</p>
<h2 id="caveat." tabindex="-1">Caveat.</h2>
<p>Of course this does mean you could be duplicating some of the outputted CSS but a bonus means you could also be more specific.</p>
<h2 id="but..." tabindex="-1">But...</h2>
<p>Perhaps you only want to give IE6-7 a static, fixed width 'base' design and give IE8 a hybrid fixed/responsive site. With this way of writing your code, you now can do. Easy to create and using this technique easliy maintainable.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Your website stinks on mobile...</title>
      <link href="https://www.alwaystwisted.com/articles/your-website-stinks-on-mobile.html"/>
      <updated>2012-06-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/your-website-stinks-on-mobile.html</id>
      <content type="html">
        <![CDATA[
        <p>You should stop being such a lazy-assed developer.</p>
<p>There's just too many devices out there to just test on your resizable desktop browser for any excuse not to test on at least the device(s) you own.</p>
<p>Almost everyday I visit a new site or a redesign that effectively breaks in some fashion on my iPhone (other phones are available and yes I have some of those too).</p>
<p>You see, no matter how it looks on your desktop browser. When viewing it on a mobile device it can break. It could be a really long url in a blog post comment, it could be the <code> in your latest blogpost or it could be that new demo video that's breaking out of the devices viewport. All of which, I feel, makes your lovely collection of pixels tarred with a smack of laziness.</p>
<p>You should be testing on the device(s) you're developing your site for. It's 2012, you've got to step up your game. <a href="http://www.lukew.com/ff/entry.asp?1506">Mobile is getting big</a> so test on what you have or can beg, borrow but not steal. If you don't you're being incredulouos to your craft and this profession.</p>
<h2 id="a-back-story." tabindex="-1">A back story.</h2>
<p>When I saw these issues on my iPhone, I used to tweet the sites creator and try and explain what's broken as succinctly as a I could. Sometimes this was greatly appreciated, mostly it 'fell on deaf ears'. So after months of slowly getting 'less interested' in trying to help I've generally stopped. It's not my problem that you've been lazy in the development of the site not to test it on (at least one of) the devices you're expecting it to work on.</p>
<p>Take your head out of your ass and test your site on all the things.</p>
<h2 id="what-can-be-done." tabindex="-1">What can be done.</h2>
<p>Well, luckily there's many things you can do to start and, I repeat, you should. I'm sure you've got an internet enabled device. You might even be reading this post on your iPhone or 'droid. So why aren't you testing every aspect of your site on it, thinking of every eventaullity that could break it?</p>
<p>You may only have one phone, but you should really consider getting more. There are a <a href="http://bradfrostweb.com/blog/mobile/test-on-real-mobile-devices-without-breaking-the-bank/">couple</a> of <a href="http://stephanierieger.com/strategies-for-choosing-test-devices/">posts</a> on which devices you should consider choosing and I've got a little tumblog on other <a href="http://mytestsuite.tumblr.com/">peoples test suites</a> so you can get an idea of what other developers are using.</p>
<h2 id="buy-devices." tabindex="-1">Buy Devices.</h2>
<p>You need more than one device. I'd at least recommend getting an iOS device and a 'droid. You don't need an iPhone and you don't need it all to be new. A 2nd hand iPod Touch would work just as well. For your Android device, there's plenty to choose, plenty of ever differing operating systems also. Going with some recent <a href="http://developer.android.com/resources/dashboard/platform-versions.html">platform version statistics</a> I'd go with Android 2.3.3. A quick note is to not purchase a 'droid that uses GetJar as it's app marketplace. Invariably you can't download any other browsers.</p>
<h2 id="install-those-browsers." tabindex="-1">Install those browsers.</h2>
<p>For iOS you'll get mobile Safari but also <a href="http://www.google.co.uk/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CIMBEBYwAA&amp;url=http%3A%2F%2Fitunes.apple.com%2Fgb%2Fapp%2Fopera-mini-web-browser%2Fid363729560%3Fmt%3D8&amp;ei=DsjJT7G2H8KW8QO6kPEC&amp;usg=AFQjCNFO5IO_FaVkTJ4R-gkxSkeZYImKOQ&amp;sig2=25AJ9JQ6H4KC2RHLZQKfIQ">download</a> Opera mini. For Android you've a plethora of choice. It comes with it's own 'Browser' but you should install Opera mini, Opera Mobile, Dolphin HD and Dolphin mini. If you have or purhcase a <a href="http://www.mozilla.org/en-US/mobile/platforms/">'qualifying' device</a> you could and should also install Firefox for mobile.</p>
<h2 id="hiding-in-the-shadows." tabindex="-1">Hiding in the shadows.</h2>
<p>Recently launched <a href="http://labs.adobe.com/technologies/shadow/">Adobe Shadow</a> allows you to test, inspect and preview your desgins on your iOs or Android device. It allows you to edit on your laptop/desktop and see what's being rendered on your device. Which in turn will make your development that little bit quicker and will help iron out the creases of your design you've previoulsy just tested on a resizable browser.</p>
<h2 id="emulates." tabindex="-1">Emulates.</h2>
<p>Another recently launched product is Opera Softwares <a href="http://www.opera.com/developer/tools/mobile/">Opera Mini Emulator</a> which allows you to view how your site could look on several devices. You can pair this up with Opera's <a href="http://www.opera.com/developer/tools/">Dragonfly</a> to edit the code too (a <a href="http://www.youtube.com/watch?v=YHwiaH8Z5vA">video demo of Dragonfly</a> from Patrick).</p>
<p>If you haven't got an iOS device and can't afford to purchase a iPod Touch you could try the emulator that comes with Xcode as well. Here's a nice little how too on <a href="http://kevinthompson.info/blog/iphone-and-ipad-browser-testing-using-the-ios-simulator/">getting it set up</a>.</p>
<h2 id="blackberries." tabindex="-1">Blackberries.</h2>
<p>Well they're getting cheaper to buy 2nd hand or you could use the <a href="http://us.blackberry.com/developers/resources/simulators.jsp">emulator</a> but you should really think about them in your designs. For example, there v5.0 browser (found on the populat <a href="http://uk.blackberry.com/devices/blackberrycurve8520/features.jsp">8520</a>) doesn't suppoer CSS3 media queries very well. So your responsive design could look pretty crappy.</p>
<h2 id="you-have-to-touch-it." tabindex="-1">You have to touch it.</h2>
<p>As well as what your site 'looks like' on a mobile device, without testing on them you won't know how 'they feel'. Your finger or thumb is not a mouse cursor. Your sites visitors precision will be off. Your site might be easily accessible by touch but it could be a pain in the frickin' ass when using a thumbwheel.</p>
<h2 id="if-you-must." tabindex="-1">If you must.</h2>
<p>If you find yourself only resorting to using Chrome or even just for quick things then <a href="http://twitter.com/paulmist">Paul Mist</a> showed me this little <a href="https://gist.github.com/2857377">bit of JavaScript</a> that you can save as a bookmark to create a 'iPhone sized' browser window to test in.</p>
<h2 id="do-as-much-as-you-can-and-at-least-do-something." tabindex="-1">Do as much as you can and at least do something.</h2>
<p>Going back to basics. Just please, test your sites design on whatever you have to hand and not just on your browser of choice.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>How I&#39;m rolling my media queries</title>
      <link href="https://www.alwaystwisted.com/articles/how-im-rolling-my-media-queries.html"/>
      <updated>2012-05-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/how-im-rolling-my-media-queries.html</id>
      <content type="html">
        <![CDATA[
        <p>As I've previously mentioned, I start with a default set of <a href="http://alwaystwisted.com/post.php?s=2012-04-28-a-common-set-of-breakpoints-to-start">common breakpoints</a> when I'm creating my responsive stylesheets. Recently you may also have seen a post where I discuss the exciting <a href="http://alwaystwisted.com/post.php?s=2012-05-05-everyday-im-bubbling-with-media-queries-and-less">Media Query bubbling</a> that's available in LESS. So I thought I'd write a quick post on how I'm currently rolling out media queries in my stylesheets.</p>
<h2 id="snippets" tabindex="-1">Snippets</h2>
<p>First off, I used Espresso for my code editor. I know there's many a code editor available and having spent almost 12 years in dreamweaver prior to purchasing, this app suits my 'workflow'.</p>
<p>So, to start I've created several <a href="http://wiki.macrabbit.com/index/Snippets/">snippets</a> in the app for my common breakpoints which are 320, 480, 600, 768, 900, 1100 &amp; 1300px (although these are stipulated in ems based on 1em = 16px).</p>
<p>This means that if I type 320 then hit 'tab' the following code gets put in place</p>
<p>@media screen and (min-width:  20em) {</p>
<p>I can then write the rules that I'd like within this query and close it at the end. I have also created a 'blank' media query snippet for 'ordinary' media queries and device media queries. Which are mq + 'tab' and dmq + 'tab' that will give you this code</p>
<p>@media only screen and (min-width :  ) {
}</p>
<p>@media only screen and (min-device-width :  ) {
}</p>
<h2 id="bubbles%3F" tabindex="-1">Bubbles?</h2>
<p>Like I said at the start, I'm now implementing the use of media query 'bubbling' in my LESS files. For me that keeps all the elements and there selectors close together. Not in seperate 'media query files. All together, under one roof and with the media query within it so I can see at ease what I'm playing with and if I've already added 10px of padding to that element already, straight away. Without having to find it and check.</p>
<h2 id="sorted!" tabindex="-1">Sorted!</h2>
<p>So I can quickly create my CSS using LESS. I can start with my base styles. Quickly add a media query (common or not) with snippets so that I can alter what's needed when it starts to look <a href="https://twitter.com/brad_frost/statuses/191977076000161793">shit</a>. I can see at a glance what element has what CSS effecting it and where and it's simple (with snippets) to add as many media queries as I so wish. So I could end up with a LESS file like this snippet.</p>
<p>header {
body: background-color: blue;
 @media screen and (min-width:  20em) {
body: background-color: red;
}</p>
<p>@media screen and (min-width:  37.5em) {
body: background-color: green;
}</p>
<p>@media screen and (min-width:  48em) {
body: background-color: blue;
}</p>
<p>@media screen and (min-width:  1176px) {
body: background-color: orange;
}
}</p>
<h2 id="ta-da!" tabindex="-1">Ta-da!</h2>
<p>Not the greatest blogpost I know, but I'd just thought I'd share a little insight into how I'm 'doing it' with responsive web design, LESS and media query bubblin'</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Content Choreography Mixins In LESS</title>
      <link href="https://www.alwaystwisted.com/articles/content-choreography-mixins-in-less.html"/>
      <updated>2012-05-17T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/content-choreography-mixins-in-less.html</id>
      <content type="html">
        <![CDATA[
        <p>With the new fangled-ness of CSS3 we've been given a treat in box-orient and box-ordinal group, at some point last year I started creating a <a href="http://alwaystwisted.com/backstage/css3-box.html">little demo</a> for a nice reponsive idea for mobile first navigation but stopped (for some reason that escapes me).</p>
<h2 id="recently." tabindex="-1">Recently.</h2>
<p>Just recently that <a href="https://twitter.com/jordanmoore">Jordan Moore</a> created a <a href="http://www.jordanm.co.uk/post/21863299677/building-with-content-choreography">lovely little post</a> on content choreography that takes these two CSS3 selectors and (with a mobile first, responsive approach) <a href="http://www.jordanm.co.uk/contentchoreography">demontstrates</a> <a href="http://www.jordanm.co.uk/contentchoreographydemo">how</a> to move your content for various devices.</p>
<h2 id="just-today." tabindex="-1">Just Today.</h2>
<p>Today whilst perusing the twitters, I saw this tweet from Jordan -</p>
<blockquote>
<p>Content Choreography made even easier with @<a href="https://twitter.com/irishstu">irishstu</a>'s lovely little SASS mixin - <a href="http://t.co/x1YdREa8" title="http://blog.woop.ie/post/23227066135/content-choreography-mixin">blog.woop.ie/post/232270661…</a> <a href="https://twitter.com/search/%2523rwd">#rwd</a></p>
<p>— Jordan Moore (@jordanmoore) <a href="https://twitter.com/jordanmoore/status/203114164120596481">May 17, 2012</a></p>
</blockquote>
<p>I soon tweeted back saying that I'll knock this up in LESS later, and here is that post.</p>
<h2 id="to-start-with." tabindex="-1">To start with.</h2>
<p>The first LESS mixin we will create is for the container (probably <body>) so that it'll initiate the relevant box-orient -</p>
<p>.boxit(@box-dir) {
display:-webkit-box;
display:   -moz-box;
display:        box;</p>
<p>-webkit-box-orient:@box-dir;
-moz-box-orient:@box-dir;
-ms-box-orient:@box-dir;
box-orient:@box-dir;
}</p>
<p>So for the @box-dir in this mixin you can choose horizontal, vertical, inline-axis, block-axis or inherit&gt; For more information check out the <a href="https://developer.mozilla.org/en/CSS/box-orient">MDN post here</a>.</p>
<p>For example, your LESS file would contain this  -</p>
<p>body { .boxit(vertical); }</p>
<p>Which would give the resulting CSS -</p>
<p>body {
display:-webkit-box;
display:   -moz-box;
display:        box;</p>
<p>-webkit-box-orient:vertical;
-moz-box-orient:vertical;
-ms-box-orient:vertical;
box-orient:vertical;
}</p>
<h2 id="now%2C-order-it." tabindex="-1">Now, order it.</h2>
<p>The second mixin allows you to specifiy where you wish the content to be. The LESS code for this is -</p>
<p>.box-order(@box-order-number: 1) {
-webkit-box-ordinal-group: @box-order-number;
-moz-box-ordinal-group: @box-order-number;
-ms-box-ordinal-group: @box-order-number;
box-ordinal-group: @box-order-number;
}</p>
<p>This allows you to easily define the number order in the chosen box-orient. So you'd write your LESS like this -</p>
<p>h1 { .box-order(3); }
h2 { .box-order; }</p>
<p>Which would give this result -</p>
<p>h1 {
-webkit-box-ordinal-group: 3;
-moz-box-ordinal-group: 3;
-ms-box-ordinal-group: 3
box-ordinal-group: 3;
}</p>
<p>h2 {
-webkit-box-ordinal-group: 1;
-moz-box-ordinal-group: 1;
-ms-box-ordinal-group: 1;
box-ordinal-group: 1;
}</p>
<h2 id="and-there-we-have-it." tabindex="-1">And there we have it.</h2>
<p>Here's the LESS version of the <a href="http://blog.woop.ie/post/23227066135/content-choreography-mixin">Sass</a> version from eariler today</p>
<h2 id="an-update-(12%2F06%2F12)" tabindex="-1">An Update (12/06/12)</h2>
<p>After creating this post I thought that, really, I should include the swift becoming new CSS3 <a href="https://developer.mozilla.org/en/Using_flexbox">flexbox</a> code, as what's written above, although 'current' in some browsers, will soon be depreciated.</p>
<p>So to use the new hawtness of <a href="http://dev.w3.org/csswg/css3-flexbox/">CSS3 Flexbox</a> we first, again, need to (using LESS) set it up in the body.</p>
<p>.flexit(@flex-dir) {</p>
<p>display:-webkit-flex;
display:-moz-flex;
display:-ms-flex;
display:-o-flex;
display: flex;</p>
<p>-webkit-flex-direction:@flex-dir;
-moz-flex-direction:@flex-dir;
-ms-flex-direction:@flex-dir;
-o-flex-direction:@flex-dir;
flex-direction:@flex-dir;</p>
<p>}</p>
<p>As you can see that where we had display: box; the new spec is display: flex;</p>
<p>I've included a new mixin as <a href="https://developer.mozilla.org/en/CSS/flex-direction">flex-direction</a> has different properties than <a href="https://developer.mozilla.org/en/CSS/box-orient">box-orient</a>.</p>
<p>Also instead of box-ordinal-group, the new spec uses a simple single word, order. Because the value is still numeric we can fit both spec's (if you wanted to) into the same mixin.</p>
<p>.box-order(@box-order-number: 1) {</p>
<p>-webkit-box-ordinal-group: @box-order-number;
-moz-box-ordinal-group: @box-order-number;
box-ordinal-group: @box-order-number;</p>
<p>-webkit-box-order: @box-order-number;
-moz-order: @box-order-number;
-ms-order: @box-order-number;
-o-order: @box-order-number;
order: @box-order-number;</p>
<p>}</p>
<p>Using these two new mixins you're now set for world dominence, except Opera, they're not supporting it, yet (but I've included for prefix for when they do).</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Screwing the srcset</title>
      <link href="https://www.alwaystwisted.com/articles/screwing-the-srcset.html"/>
      <updated>2012-05-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/screwing-the-srcset.html</id>
      <content type="html">
        <![CDATA[
        <p>As much as I wasn't convinced with how the addition of srcset was included in the <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/embedded-content-1.html#attr-img-srcset">spec</a>, what a difference a day makes.</p>
<p>At first I was not a fan of it's appaling syntax, but after a quick email from <a href="http://twitter.com/adactio">Jeremy</a> in the <a href="http://lists.w3.org/Archives/Public/public-whatwg-archive/2012May/0320.html">WhatWG email list</a> I was a little more convinced.</p>
<h2 id="in-fact." tabindex="-1">In Fact.</h2>
<p>Before we go any further you should really read <a href="http://adactio.com">Jeremy's</a> fantastic <a href="http://adactio.com/journal/5474/">post</a> of calmness and tranquility in explaining what has happened up until this point.</p>
<p>Back yet? You migh want to read Dr. <a href="http://twitter.com/brucel">Bruce's</a> <a href="http://html5doctor.com/html5-adaptive-images-end-of-round-one/">post</a> to.</p>
<p>You there? Cool. Now my issue is with the current <a href="http://odin.s0.no/web/srcset/polyfill.htm">polyfill</a> that 'showed itsself' in my timeline on the twitter this morning.</p>
<h2 id="a-srcset-polyfill" tabindex="-1">A srcset polyfill</h2>
<p>Ok, There's quite a bit of the polyfill I don't like so let's make a start ok? Ready? Let's go.</p>
<p>Let's have a look at the polyfill's HTML</p>
<p><img alt='' srcset='big.png 1100w, medium.png 500w, small.png 200w' style='display:none' /> <noscript>
<img src='small.png' alt='Noscript alt'></noscript></p>
<h3 id="no" tabindex="-1">no <img src=''></h3>
<p>In the polyfill there is not an initial image file like there is in the spec. I don't think that's good at all, it's not very '<a href="http://futurefriend.ly/">future friendly</a>'. So to fix that, let's add it to the HTML. While we're at it, let's tidy it up a little too.</p>
<p><img src='small.png'
      srcset='big.png 1100w,
              medium.png 500w,
              small.png 200w'
          alt='alt text'
        style='display:none'
    />
<noscript><img src='small.png' alt='Noscript alt'></noscript></p>
<p>That's better, but that's not it is it?</p>
<h3 id="display%3A-none%3B-is-utter-filth" tabindex="-1">Display: none; is utter filth</h3>
<p>As you can see in the HTML above the polyfill has put display: inline; inline with the HTML rather than within the CSS. Let's fix that.</p>
<p>So first up let's remove it from the HTML</p>
<p><img src='small.png'
      srcset='big.png 1100w,
              medium.png 500w,
              small.png 200w'
          alt='alt text'
    />
<noscript><img src='small.png' alt='Noscript alt'></noscript></p>
<p>Now we've done that, let's add it to the CSS</p>
<p>img { display: none; }</p>
<p>Nice, sorted right?</p>
<h3 id="switching-around-the-javascript" tabindex="-1">Switching around the JavaScript</h3>
<p>At the bottom of the JS file, where the original polyfill is hacking around the <img> tag it does this -</p>
<p>// Remove the stupid display:none made to hide the alt-text
img.style.display = ''</p>
<p>As we've now put display:none; in the CSS we need to change that by simply added 'block' where '' is (let's change the comment too) -</p>
<p>// Change the style of the <img /> element to display decided upon image
img.style.display = 'block'â€‹</p>
<p>This now means that the polyfill will display the <img>. Good? Well, just one more thing.</p>
<h3 id="no%2C-no%2C-no%2C-no%2C" tabindex="-1">No, no, no, no, <noscript></h3>
<p>At the end of the polyfill HTML code is the <noscript> tag with the small images so there's a fallback for browsers that don't have JavaScript enabled. Because we've added display: none; to the <img> elements in CSS, the <noscript> <img>'s will be 'hidden' too. So we need to change that in the CSS, like this -</p>
<p>noscript img { display: inline; }</p>
<p>Excellent, that's great, isn't it? We fixed the internet right?</p>
<h2 id="ta-da!" tabindex="-1">Ta-Da!</h2>
<p>So. Here's <a href="http://jsfiddle.net/sturobson/2t3xt/16/">all the code</a> for the polyfill that I've edited to this state.</p>
<h3 id="but%2C-two-images%3F" tabindex="-1">But, Two images?</h3>
<p>Unfortunately because <a href="http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/">how browsers work</a> this polyfill has the bastard audacity to download two images when all we need is one. This is because of our using of display:none; and calling an image at first then, with Javascript, calling the 'appropriate' image. That's an extra http request that could be costly and also some more page weight that could be detrimental. For the short term, that's something that could be ok though right?</p>
<h2 id="well%2C-not-really..." tabindex="-1">Well, not really...</h2>
<p>That's about as far as my 'knowledge and understanding' can probably take it. I'm sure it can be improved upon, refactored, edited, fucked with and corrected. I do feel it's a little bit 'cleaner and meaner' than the original polyfill I've edited.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Create a responsive mobile first menu</title>
      <link href="https://www.alwaystwisted.com/articles/create-a-responsive-mobile-first-menu.html"/>
      <updated>2012-05-14T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/create-a-responsive-mobile-first-menu.html</id>
      <content type="html">
        <![CDATA[
        <h1 id="part-2-of-a-series-looking-at-progressively-enhanced%2C-mobile-first%2C-reponsive-navigation" tabindex="-1">Part 2 of a series looking at progressively enhanced, mobile first, reponsive navigation</h1>
<p>In the <a href="http://alwaystwisted.com/post.php?s=2012-05-12-create-a-pure-css-menu-button">first part of this mini series</a> we looked at creating a menu icon for what I believe to be the <a href="http://stuffandnonsense.co.uk/blog/about/we_need_a_standard_show_navigation_icon_for_responsive_web_design">best solution</a> for your site's <a href="http://bradfrostweb.com/blog/web/responsive-nav-patterns/">mobile navigation</a>.</p>
<p>The outcome was to create an icon by creating an HTML element similar to this -</p>
<p>HTML</p>
<div id='nav-btn'></div>
<p>Which would then be styled with CSS like this -</p>
<p>CSS</p>
<p>#nav-btn {</p>
<p>background: transparent; 
border-bottom: 23px double #121212; 
border-top: 8px solid #121212;
height: 7px; 
width:37px;
}</p>
<p>Result</p>
<h2 id="making-an-example." tabindex="-1">Making an example.</h2>
<p>Ok, so let's start making a quick example page with some links that we're going to want to manipulate with this button. I could bore you with the HTML and CSS of this but I'm sure you know how to do that kinda stuff, and if not. You can see it from the resulting JSFiddle below -</p>
<h2 id="querying-your-users-viewport." tabindex="-1">Querying your users viewport.</h2>
<p>Now for this example, I only want the resulting show/hide menu icon to work on small viewports. Not only do I want to only have this working for small viewports (less than 767px for arguements sake) I was also only want it to work on devices such as an iPhone or Android mobile phone. Therefore whereas we would normally use this kind of media query -</p>
<p>@media only screen and (min-width: 240px) {
/* CSS Rules to go here */
}</p>
<p>We are instead going to define a media query as follows that should only affect viewports found on popular mobile phones, like this -</p>
<p>@media only screen and (min-device-width: 1px) and (max-device-width: 767px) {
/* CSS Rules to go here */
}</p>
<p>The min-device-width and max-device-width media query rules struggle to work in Android 2.2 so to combat this make sure you've got something similar to this in your HTML</p>
<p><meta content='width=device-width,initial-scale=1' name='viewport' /></p>
<p>So with this media query we're going to hide the nav element and restyle it.</p>
<p>An updated example (note: this will only look different on your mobile device) -</p>
<h2 id="but-first%2C-where's-that-menu-button-gone%3F" tabindex="-1">But first, where's that menu button gone?</h2>
<p>In the HTML of the last code example I have not included the DIV for the button. This is because it is going to be added with JavaScript and jQuery. This makes our original HTML cleaner and means your site will be more <a href="http://www.alistapart.com/articles/understandingprogressiveenhancement/">progressively enhanced</a> and will <a href="http://dev.opera.com/articles/view/graceful-degradation-progressive-enhancement/#gracefulprogressivenutshell">degrade gracefully</a> when the user has JavaSCript disabled or they're a blackberry user *winks*.</p>
<h2 id="getting-the-javascript-going." tabindex="-1">Getting the Javascript going.</h2>
<p>So, we're going to add the navigation (menu) button with some JavaScript/jQuery. To do this we're going to use jQuery's prepend, like this -</p>
<p>$('#container').prepend('<div id='nav-btn'></div>');</p>
<p>Well that's all well and good, but.</p>
<h2 id="c'mon%2C-c'mon%2C-c'mon%2C-touch-me." tabindex="-1">C'mon, c'mon, c'mon, Touch me.</h2>
<p>The menu icon is perfect for touch, not so much for a device that'll recognise the media queries but doesn't have touch. So we're going to throw that bit of jQuery into an if statement in JavaScript to only appear if the device has touch. Like this -</p>
<p>if ('ontouchstart' in document.documentElement)</p>
<p>// It's a touch screen device.</p>
<p>// create the button div
$('#container').prepend('<div id='nav-btn'></div>');
}</p>
<p>else 
{
}</p>
<p>So to tie-in with our device-width media queries this should now show the menu button when viewed on a touch screen device which's viewport is no bigger than 767px.</p>
<h2 id="more-styling%3F-more-javascript%2Fjquery%3F" tabindex="-1">More Styling? More JavaScript/jQuery?</h2>
<p>I want to style the navigation links differently if the device is touch enabled. As much as I have previously said how I dislike a <a href="http://alwaystwisted.com/post.php?s=2011-02-20-dont-let-your-menu-take-over">screen full of links</a> having a menu button that shows and hides the navigation is screaming out for nice big links for our chuby fingers to tap, But to progressively enhance this bad boy we only want it changed on devices that have JavaScript enabled. Therefore we're going to add a class the contents #container. Whilst we're at it let's add the show/hide jQuery code too. Like this -</p>
<p>if ('ontouchstart' in document.documentElement)
{
// It's a touch screen device.</p>
<p>// add claas of touch to container for the CSS 
$('#container').addClass('touch');</p>
<p>// create the button div
$('#container').prepend('<div id='nav-btn'></div>');</p>
<p>// make the button div a toggle show/hide$('#nav-btn').click(function(){
$('nav').toggle();
return false;
})
}</p>
<p>else 
{
}</p>
<p>Now we add the .touch to the relevant CSS. Here's the updated example.</p>
<p>Having a quick play with this I noticed the dreaded <a href="http://paulirish.com/2009/avoiding-the-fouc-v3/">FOUC</a>. So, first I added a 'noJs' class to my HTML then included the following code to swap it with just 'JS' if JavaScript is enabled</p>
<p><script>
(function(H){H.className=H.className.replace(/bnojsb/,'js')})
(document.documentElement)
</script></p>
<p>After this I changed the display: none; attirbute for the <nav> element to work if the document has a JS class which gets rid of the FOUC and degrades nicely as well.</p>
<h2 id="you've-hidden-it%3F-but%3F" tabindex="-1">You've hidden it? But?</h2>
<p>Of course, hiding the <nav> element with display: none; when JavaScript is enabled will hide it regardless of whether the device viewing the site has touch capability or not. Therefore we need to add something to the else statement in the Javascript. That's easily rectifided as shown in this example code -</p>
<p>if ('ontouchstart' in document.documentElement)
{
// It's a touch screen device.</p>
<p>// add claas of touch to container for the CSS 
$('#container').addClass('touch');</p>
<p>// create the button div
$('#container').prepend('<div id='nav-btn'></div>');</p>
<p>// make the button div a toggle show/hide$('#nav-btn').click(function(){
$('nav').toggle();
return false;
})
}</p>
<p>else 
{
// shown navigation menu
$('nav').css('display','block');
}</p>
<p>Here's an updated fiddle including all that fun code -</p>
<h2 id="it's-not-over-until-you-open-it-in-opera-mini" tabindex="-1">It's not over until you open it in Opera Mini</h2>
<p>Although I've managed to get this working in MobileSafari (iOS 5.1.1), a Android 2.2,2.2.1,2.3.6 and 4.0 browser and Opera Mobile. Opera mini was giving me a headache.</p>
<p>For some reason (to which I guess it's because it is a <a href="http://en.wikipedia.org/wiki/Opera_Mini">proxy browser</a>) Opera mini doesn't create the nav-btn div and prepend it to it's #container. Doing this means an Opera mini user won't see the menu AT ALL unless they've got JavaScript disabled.</p>
<p>Having a quick hunt around the internet I found that you can target the browser using JavaScript. So adding this code would then give you the links back, but with out the additional styling also. If you wanted you could then define these again with another class and apply that too. But for now -</p>
<p>if (operamini)
{
// remove .touch class for opera mini as it can't create the #nav-btn element
$('#container').removeClass('touch');
}</p>
<p>else
{</p>
<p>}</p>
<h2 id="that's-all-folks!" tabindex="-1">That's all folks!</h2>
<p>There we pretty much have it, a menu button that's created with CSS added with JavaScript that if enabled alse changes the styling of your navigation to suit your touch enabled device and your fat fingers.</p>
<p>Here's one last fiddle -</p>
<p>But if you want to go straight to a page just to test it on your device(s) then I've hosted it on <a href="http://alwaystwisted.com/playground/1.html">my site here</a> too.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Create a pure CSS menu button</title>
      <link href="https://www.alwaystwisted.com/articles/create-a-pure-css-menu-button.html"/>
      <updated>2012-05-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/create-a-pure-css-menu-button.html</id>
      <content type="html">
        <![CDATA[
        <h1 id="part-1-of-a-series-looking-at-progressively-enhanced%2C-mobile-first%2C-reponsive-navigation" tabindex="-1">Part 1 of a series looking at progressively enhanced, mobile first, reponsive navigation</h1>
<p>If you've <a href="http://twitter.com/sturobson">followed me</a> on the twitters for some time, you'll know my thoughts on the <a href="http://stuffandnonsense.co.uk/blog/about/we_need_a_standard_show_navigation_icon_for_responsive_web_design">best solution</a> for <a href="http://bradfrostweb.com/blog/web/responsive-nav-patterns/">mobile navigation</a>. In short. I hate the idea of using a <a href="http://www.stuffandnonsense.co.uk/blog/about/the_select_menu_navigation_pattern"><select></a> to 'fix' your navigation. Although it's a great idea that's been <a href="https://github.com/mattkersley/Responsive-Menu">created</a>. I feel that the extra 'tap' to select the link, the inherent difference in styling and implementation across devices make me believe that -</p>
<blockquote>
<p>Using <select> for mobile navigation is a developer's answer to a designer's problem.</p>
</blockquote>
<p>Now, I've also been thinking about how much we should be thinking about what we're actually giving the person with their (insert any handheld mobile device but) iPhone.</p>
<h2 id="some-options." tabindex="-1">Some options.</h2>
<p>You see, creating a new image for the menu icon could create another http request (although you could (and should) create a css sprite of  'ALL THE THINGS' like that, but you would still have that extra kb to download).</p>
<p>You could use a <a href="http://css-tricks.com/examples/IconFont/">icon font</a>, but again this would create another http request and also a file of which you don't use all of it's parts. Although it can scale nicely (or <a href="http://simurai.com/post/19895985870/icon-sharpness-limbo">not</a>) for a menu button for your handheld touch device it's a little overkill.</p>
<h2 id="door-number-3." tabindex="-1">Door number 3.</h2>
<p>I think, one way of creating your 3 line mobile navigation menu button is to use CSS. Pure CSS. It'll add a few lines of code to your CSS file but would be a little nicer for your user to not have to download more stuff just for one button.</p>
<p>So to create a simple 3 line menu button you'd need to write something akin to this -</p>
<p>HTML</p>
<div id='lines'></div><p>CSS</p>
<p>#lines { 
    border-bottom: 17px double black; 
    border-top: 6px solid black; 
    content:'';
    height: 5px; 
    width:30px;
}â€‹</p>
<p>Result</p>
<p>Now, the only issue with creating something like this is an empty div, that's pretty crappy but I'll get to that in a later post. Let's just concentrate on creating cool CSS only menu buttons.</p>
<p>Maybe for this we want to add a border around it to make it 'look' more like a button. We can do this by adding a class to the <div> and changing around the CSS to include a :before rule.</p>
<p>HTML</p>
<div id='lines' class='btn'></div><p>CSS</p>
<p>.btn {
position: relative;
margin-top:2%;
border: 2px solid black;
border-radius: 2px;
height: 36px;
width:36px;
}
#lines:before {
border-bottom: 17px double black;
border-top: 6px solid black;
content:'';
height: 5px;
position: absolute;
right:3px;
top: 4px;
width:30px;
}</p>
<p>Result</p>
<p>Here you can see we've added a border around the lines with the class .btn. Doing it this way means that any css rules for #lines would overide them. Therefore we've used the :before pseudo selector to achieve a nice result.</p>
<h2 id="there's-more%3F" tabindex="-1">There's more?</h2>
<p>Of course there's more. Although I love the 3 lines menu, after a recent discussion on twitter, it won't really work if you're having sub navigation within the main navigation. Lots of 3 line icons all stack on each other it can get confusing . So I created some more buttons out of CSS.</p>
<h2 id="build-it%2C-break-it%2C-make-more" tabindex="-1">Build it, Break it, Make More</h2>
<p>As you can see the CSS icons are up on jsfiddle. Have a look, take them apart, make them better, make them sexier and add them to the comments.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>CSS navigation with diagonals</title>
      <link href="https://www.alwaystwisted.com/articles/css-navigation-with-diagonals.html"/>
      <updated>2012-05-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/css-navigation-with-diagonals.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/screen-shot-20120507-at-20.05.25-ck.png" alt="" loading="lazy" decoding="async"></p>
<p>Sometimes when I look at the twitters i find little requests for ideas on how to do something. I often do this to, usually for jQuery. Today <a href="http://twitter.com/markskinner_">Mark Skinner</a> wondered this -</p>
<blockquote>
<p>Any suggestions on how to achieve <a href="http://t.co/OHG1ZpK8" title="http://work.kevinleary.net/diagonal-nav/diagonal-navigation-setup.html">work.kevinleary.net/diagonal-nav/d…</a> without using the JQuery? :-)</p>
<p>— Mark Skinner (@MarkSkinner_) <a href="https://twitter.com/MarkSkinner_/status/199425235118854144">May 7, 2012</a></p>
</blockquote>
<p>As soon as I clicked the link I instantly thought that a navigation system (menu) like this could be created in pure CSS</p>
<p>I found myself with a free half hour so I thought I'd crack open <a href="http://jsfiddle.net">JSFiddle</a> and have a go to see what I could come up with. Please note: there are other online <a href="http://dabblet.com/">places</a> and <a href="http://codepen.io/">spaces</a> to quickly code up simple things, I just am so used to the 4 windows of JSFiddle it's hard to try anything else (for now).</p>
<h2 id="the-code-begins." tabindex="-1">The Code Begins.</h2>
<p>First up I obviously needed to create the HTML for the menu. I knew in my CSS I was going to be using display: inline-block; on the <li> elements so I wrote this example HTML.</p>
<ul>
    <li><a href=''>link 1</a><li>
    <li><a href=''>link 2</a></li>
    <li><a href=''>link 3</a></li>
    <li><a href=''>link 4</a></li>
<ul>
<p>What i did to the above examples was put all the <li> elements on a single line of code. Simliar to this -</p>
<ul>
    <li><a href=''>link 1</a><li><li><a href=''>link 2</a></li>
</ul>
<p>By putting the <li> in one line with no gaps we would not inherit a 4px gap that inline-block gives us by proxy.</p>
<h2 id="css-set-up." tabindex="-1">CSS Set-up.</h2>
<p>For years I've used <a href="http://twitter.com/meyerweb">Eric Meyer's</a> CSS <a href="http://meyerweb.com/eric/tools/css/reset/">Reset</a> in the various guises it pulled and only recently (the last 3-4 months) have I side-lined it for <a href="http://twitter.com/necolas">Nicolas Gallagher's</a> <a href="http://necolas.github.com/normalize.css/">Normalize</a> system. So first off this is including in pretty much every CSS file I create and (luckily) it's also included in new default JSFiddle page.</p>
<p>Secondly I now add the new cool box-sizing CSS property which that <a href="http://twitter.com/paulirish">Paul Irish</a> discusses in this <a href="http://paulirish.com/2012/box-sizing-border-box-ftw/">blogpost</a>.</p>
<p>* {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit <em>/
-moz-box-sizing: border-box; /</em> Firefox, other Gecko <em>/
box-sizing: border-box; /</em> Opera/IE 8+ */
}</p>
<h2 id="and-to-start." tabindex="-1">And to start.</h2>
<p>Next I wrote a little bit of CSS. This would be to style the <ul> and the <li> elements and can be changed to suit -</p>
<p>ul {
background: grey;
height: 60px;
padding: 10px 0 10px 40px;
width: 100%;
}</p>
<p>li {
background: orange;
float: left;
line-height: 20px;
margin-right: 30px;
padding: 10px 3px;
position: relative;
}</p>
<p>As you can see I've added a margin-right to all the</p>
<p>elements so I need to tidy that up a bit with some CSS3 Pseudo Selectors. This would be just to remove the last margin-right property from the last element-</p>
<p>li:last-of-type { margin-right: 0px; }</p>
<h2 id="triangles" tabindex="-1">Triangles</h2>
<p>Ok, so now that each navigation element has a 'block' of colour I wanted to start adding the 'diagonal' parts to it. To do this with CSS I used the :before and :after elements of CSS 2.1 and created this bit of code -</p>
<p>li:before {
background: none;
border-left: 20px solid transparent;
border-right: 0px solid transparent;
border-top: 40px solid orange;
content: '';
left: -20px;
position: absolute;
top: 0;
}</p>
<p>li:after {
border-left: 0px solid transparent;
border-right: 20px solid transparent;
border-bottom: 40px solid orange;
content: '';
height: 0;
position: absolute;
right: -20px;
top: 0;
width: 0;
}</p>
<h2 id="hover" tabindex="-1">Hover</h2>
<p>So, as it's a little bit of navigation it's best that I add some kind of hover effect to it. To do this there's some funky CSS that need's to be added so the whole kaboodle will change colour on hover.</p>
<p>First off we add display: block; to the <a> element, we might as well get rid of that nasty text-decoration too -</p>
<p>a {
color: black;
display: block;
text-decoration: none;
}</p>
<p>Now we've done that we can just change the bits we need to change for the hover effect. This would be for the actual <li> element and it's :before and :after pseudo bits too.</p>
<p>li:hover {
background: white;
cursor: pointer;
}
li:hover:before {
border-top: 40px solid white;
}
li:hover:after {
border-bottom: 40px solid white;
}</p>
<p>As you can see I've '<a href="http://www.w3.org/TR/CSS2/selector.html#selector-syntax">stacked</a>' the pseudo selectors 'on top' of each other so that when 'hovered over' the whole dang thing changes colour.</p>
<h2 id="we-could-have-finished-there." tabindex="-1">We could have finished there.</h2>
<p>Looking back at the original link Mark tweeted we can see that the first link (home) doesn't have a diagonal on the left only on the right. So to create this effect we need to add this bit of CSS -</p>
<p>li:first-of-type:before {
background: orange;
border: none;
height: 40px;
left: -10px;
width: 10px;
}</p>
<p>li:first-of-type:hover:before {
background: white;
height: 0px;
width: 10px;
}</p>
<p>This removes the border which was making the triabgle and adds a simple rectangle of colour</p>
<h2 id="a-step-roo-far%3F" tabindex="-1">A Step roo far?</h2>
<p>After doing this quickly I though it'd be nice to 'finish off' the navigation's design with a similar effect to the last</p>
<p>element. Just like this -</p>
<p>li:last-of-type:after {
background: orange;
border: none;
height: 40px;
right: -10px;
width: 10px;
}
li:last-of-type:hover:after {
background: white;
height: 40px;
width: 10px;
}</p>
<h2 id="that's-about-it." tabindex="-1">That's about it.</h2>
<p>Doing all this has created a nice little CSS navigation effect.</p>
<p>Of course there are some gotcha's.</p>
<ol>
<li>It's not 'responsive', I'm of the thinking that you'd switch up the styling of navigation for smaller viewports anyway so this wouldn't be a problem.</li>
<li>It can break, of course it can. If the menu is longer  than the viewport, it'll break. I may refine this bit. I may not.</li>
</ol>
<p>I've tidied it up a little bit and the <a href="http://jsfiddle.net/sturobson/Xxxvd/">final JSFiddle</a> is available to look around and poke at.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Everyday I&#39;m Bubbling. With Media Queries and LESS</title>
      <link href="https://www.alwaystwisted.com/articles/everyday-im-bubbling-with-media-queries-and-less.html"/>
      <updated>2012-05-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/everyday-im-bubbling-with-media-queries-and-less.html</id>
      <content type="html">
        <![CDATA[
        <p>We're all in love with <a href="http://adactio.com/journal/4523/">content first</a>, <a href="http://www.abookapart.com/products/mobile-first">mobile first</a>, insert your buzzword of choice, <a href="http://www.abookapart.com/products/responsive-web-design">responsive web design</a> aren't we? We all know that we <a href="http://alwaystwisted.com/post.php?s=2012-04-28-a-common-set-of-breakpoints-to-start">should</a> (or <a href="http://adactio.com/journal/5425/">shouldn't</a>) be using common <a href="http://css-tricks.com/snippets/css/media-queries-for-standard-devices/">breakpoints</a>.</p>
<p>We also know that we should be doing what <a href="https://twitter.com/stephenhay">Stephen Hay</a> puts so eloquantly -</p>
<blockquote>
<p>'Start with the small screen first, then expand until it looks like shit. Time to insert a breakpoint!'</p>
</blockquote>
<p>Now, we could just add that new media query breakpoint in our CSS with it's relevant min-width and even with it's max-width point like we have since we've started using media queries. Or we could get bubbling.</p>
<h2 id="pretty-bubbles-in-the-air." tabindex="-1">Pretty Bubbles in the air.</h2>
<p>With an update to <a href="https://github.com/cloudhead/less">LESS</a> in <a href="https://github.com/cloudhead/less.js/pull/634">February</a>. <a href="https://twitter.com/#!/cloudhead">Alexis</a>, the creator of LESS, included media query bubbling from a pull request. This means you can now write your LESS code with the media query within the element and when you compile it'll create a seperate media query for each one you create. So, you would now write your LESS like this -</p>
<p>header {
color: red;</p>
<p>@media only screen and (min-width : 768px) { color: green; }</p>
<p>@media only screen and (min-width : 1024px) { color: blue; }</p>
<p>}</p>
<p>section {
color: green;</p>
<p>@media only screen and (min-width : 768px) { color: blue; }</p>
<p>@media only screen and (min-width : 1024px) { color: red; }</p>
<p>}</p>
<p>After doing all our LESS like this and compiling it, it will create this, for the above example -</p>
<p>header {
color: red;
}
@media only screen and (min-width: 768px) {
header {
color: green;
}
}
@media only screen and (min-width: 1024px) {
header {
color: blue;
}
}</p>
<p>section {
color: green;
}
@media only screen and (min-width: 768px) {
section {
color: blue;
}
}
@media only screen and (min-width: 1024px) {
section {
color: red;
}
}</p>
<p>As you can see it creates a seperate media query for whatever has a media query. It doesn't 'group' them all together as we currently do when coding by hand.</p>
<p>I can see a real benefit of this being created in your stylesheet, as you can see easily what elements are being changed by what media query and how at a glance. This could be more difficult when your media queries are in seperate styleshets or in 'big chunks' or media queries.</p>
<p>Another benefit would be when we go back and look at Stephen's quote. When your design starts to 'look shit'  using this technique would be just that little be cleaner and quicker to do.</p>
<p>I've yet to do any performance or 'stress' tests on actual CSS files created this way rather than the 'big chunks' we've been creating thus far but hope to do this soon.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>The Horse Has Bolted... -o-really?</title>
      <link href="https://www.alwaystwisted.com/articles/the-horse-has-bolted-o-really.html"/>
      <updated>2012-05-03T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/the-horse-has-bolted-o-really.html</id>
      <content type="html">
        <![CDATA[
        <p>Ok, so we all know about what Opera are now <a href="http://dev.opera.com/articles/view/opera-mobile-emulator-experimental-webkit-prefix-support/">up to</a>. It's too late to continue the pontification, conjecture and gesticulation of how <a href="http://www.stuffandnonsense.co.uk/blog/about/there_i_said_it">they're wrong</a> in doing it or should be <a href="http://mattwilcox.net/archive/entry/id/1087/">doing it this way</a>. It's too late, that boat has set sail, the rocket has launched, the horse has bolted.</p>
<p>If you didn't inlude all the relevant vendor prefixes, or only included webkit's, you're an idiot. But let's not worry about that now. Let's try and build for the future.</p>
<h2 id="so-what-now%3F" tabindex="-1">So What Now?</h2>
<p>Fortunately there are lots of options, which is really good. A great choice surrounds us in prefixing the shit out of your CSS3.</p>
<p>If you, like me (currently), code your CSS up 'dry' without a preproccesor there are several online CSS3 generators that will create the appropriate prefixed CSS for the relevant property.</p>
<h2 id="to-start." tabindex="-1">To Start.</h2>
<p>CSS3 is one part of my stylesheet that I tend to write the most cleanly (in my opinion) so that it's a breeze to edit all of those prefixes as quickly as possible. Here's how I code a CSS3 property -</p>
<p>.element {
-webkit-transition: all 0.3s ease-out;  /* Saf3.2+, Chrome <em>/
-moz-transition: all 0.3s ease-out;  /</em> FF4+ <em>/
-ms-transition: all 0.3s ease-out;  /</em> IE10 <em>/
-o-transition: all 0.3s ease-out;  /</em> Opera 10.5+ */
transition: all 0.3s ease-out;
}</p>
<p>Here I've got all of the prefixes in order of property name length finally followed by the non-prefixed version. This was when a browser depreciates their prefixed version (usually when the property is stable enough in the spec.) the latest browser version will see the non-prefixed version last and override any prefixed version.</p>
<h2 id="talking-'bout-my-generators" tabindex="-1">Talking 'bout my Generators</h2>
<p>So, if you are someone who likes just typing the code in without a preprocessor you're in good luck. There are loads of CSS3 generators that can help you use the correct prefixed CSS for the property you're wanting to use. You'd go to this kind of site, do your thing, copy, go back to your editor of choice and paste. Done. You've added the correct CSS3 prefixed to the hilt, ready to fight.</p>
<p>Here's a few choice ones to use -</p>
<ol>
<li><a href="http://www.css3.me/">www.css3.me</a> - a CSS3 generator for border-radius, box-shadow, background gradients and opacity.</li>
<li><a href="http://css3please.com/">css3please.com</a> - all the CSS3 properties with editing in the browser to see what happens to the demo element.</li>
<li><a href="http://css3generator.com/">css3generator.com</a> - this is the one I use, almost daily. Nice and big for my ageing eyes.</li>
<li><a href="http://www.css3maker.com/index.html">www.css3maker.com</a> - another generator for multiple CSS3 properties which also adds appropriate CSS 2.1 properties that you may use at the same time.</li>
<li><a href="http://www.colorzilla.com/gradient-editor/">www.colorzilla.com/gradient-editor</a> - a generator for just those pesky gradients. The bastard child of CSS3 that'll make anyones stylesheet look ugly.</li>
</ol>
<h2 id="less-is-more%3F" tabindex="-1">LESS is more?</h2>
<p>If you're a LESS user, the easiest thing you can do is include <a href="http://lesselements.com/">LESS Elements</a>, if you look at the page, all you gotta do is write the CSS3 property once in LESS and when it's complied it'll add all the prefixed fun for you. Be sure that you've got the <a href="https://github.com/dmitryf/elements">latest version</a>.</p>
<p>Another option is <a href="https://github.com/danethurber/seamLESS">seamLESS</a>.</p>
<h2 id="you're-so-sass-y!" tabindex="-1">You're so SASS-y!</h2>
<p>If you like your CSS preprocessed <a href="http://thesassway.com/">The SASS Way</a> then there are two options I've been informed of by some lovely friends on the twitters. You could try <a href="http://compass-style.org/">Compass</a> or <a href="http://thoughtbot.com/bourbon/">Bourbon</a>. Just for the name, I beseech you to use Bourbon.</p>
<h2 id="prefixme." tabindex="-1">PrefixMe.</h2>
<p>If you want to write your CSS dry but don't want to add all those prefixes in by hand or by copying and pasting you could use that Lea Verou's <a href="http://leaverou.github.com/prefixfree/">Prefix free</a> where adding a 2kb file and you're ready to go. Of course there's the extra HTTP request and reliance on JavaScript to consider there too.</p>
<h2 id="what-next%3F" tabindex="-1">What next?</h2>
<p>I don't know, what I do know is that if you're not including all the relevant prefixes that are possibly required for the CSS3 property you want to use you are being disingenous to your craft and tarnishing us all with the same brush and fate that leads to actions like that taken by Opera.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>When your viewport lies...</title>
      <link href="https://www.alwaystwisted.com/articles/when-your-viewport-lies.html"/>
      <updated>2012-04-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/when-your-viewport-lies.html</id>
      <content type="html">
        <![CDATA[
        <p>You may be aware that a while back when that <a href="http://twitter.com/stephanierieger">Stephanie Rieger</a> posted <a href="http://stephanierieger.com/strategies-for-choosing-test-devices/">'Strategies for choosing test devices'</a> I decided to throw up a simple tumblr blog with developer's <a href="http://mytestsuite.tumblr.com/">device testing suite</a> (please add yours so that there'd be a small resource for helping others to decide what to buy.</p>
<p>About the same time I started researching and purchased a Samsung Galaxy Europa on the magical eBay. There really is a bargain to be had if you look hard enough. I managed to get this for a bargain price of £35.</p>
<h2 id="a-back-story" tabindex="-1">A back story</h2>
<p>Also at the same time I was embarking on a 120 hour project for a start up I'm now a co-founder of where, initially, I was the front-end developer turning the PSD's into a nice HTML/CSS/jQuery web system for the back-end to 'plug into'.</p>
<p>During the many skype conversations I managed to get agreed an attempt at an 'responsive' version of the fixed width designs.</p>
<h2 id="what-did-i-just-buy%3F" tabindex="-1">What did I just buy?</h2>
<p>So in the preliminary coding of the designs I thought I'd check it out on my Android device (the Eurpoa). When I ordered the mobile I knew that it'd be a device that was 240px wide and 320px high (in portrait). I thought that it'd be great to have that because there's quite a few devices that have this screen size.</p>
<p>What I wasn't expecting was for it to 'spoof' itself in thinking that it's actual viewport is 320x401 (in portrait). This makes everything a lot smaller. My hands are not the chubbiest of things and it's a real difficulty in typing in a domain name so 'pushing' buttons and navigating around a site that's 'smaller' because of this was kinda hard.</p>
<h2 id="real-devices" tabindex="-1">Real devices</h2>
<p>So case in point. It really is benificial to <a href="http://bradfrostweb.com/blog/mobile/test-on-real-mobile-devices-without-breaking-the-bank/">'test on a real device'</a>. Without doing this I could have made potential users struggle.</p>
<h2 id="human-interface-guidelines" tabindex="-1">Human Interface Guidelines</h2>
<p>I'm a real big fan of Apples <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html">guidelines</a>, although aimed for iOs applications I think that a lot of it's 'sizing of things' can be carried across to your small/narrow/mobile/device viewport designs. Also worth a read is this fantastic article about the <a href="http://aentan.com/design/new-visual-proportions-for-the-ios-user-interface/">visual proportions of iOS</a>. Of course, again, these guidelines are for a specific 'fixed width' kind of design but a lot of it can carry over within your responsive development even if device viewports can be quite an <a href="http://stephanierieger.com/the-trouble-with-android/">accumalation</a>.</p>
<h2 id="so%2C-be-careful-out-there" tabindex="-1">So, be careful out there</h2>
<p>Just because it works on your iPhone, it maybe squashed on a smaller viewport (or a smaller device lying to you), testing in the browser is great for the intial part of your responsive tool kit but try and get that design tested on as many devices as you can as often as you can. Your viewport maybe different to what you perceive.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A common set of breakpoints to start</title>
      <link href="https://www.alwaystwisted.com/articles/a-common-set-of-breakpoints-to-start.html"/>
      <updated>2012-04-28T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-common-set-of-breakpoints-to-start.html</id>
      <content type="html">
        <![CDATA[
        <p>On Thursday (26/04/12) the fantabulous <a href="http://twitter.com/adactio">Jeremy Keith</a> wrote a short post on <a href="http://adactio.com/journal/5425/">common breakpoints</a> in responsive web design where he expands his thoughts on a question asked to <a href="http://twitter.com/beep">Ethan Marcotte</a> in a <a href="http://www.netmagazine.com/interviews/ethan-marcotte-answers-your-responsive-web-design-questions">Q&amp;A article</a> on the .net magazines's website.</p>
<p>Ethan was asked -</p>
<blockquote>
<p>'What devices (smartphones/tablets) and breakpoints do you typically develop and test with?'</p>
</blockquote>
<p>His retort can be summed up just by the last sentence of the response -</p>
<blockquote>
<p>'...we should focus on breakpoints tailored to the design we’re working on.'</p>
</blockquote>
<p>Where as I completely agree that we shouldn't be just 'designing' sites for specific devices. For me it's quite hard to not think about how something would look on a popular device viewport.</p>
<h2 id="how-i-like-it..." tabindex="-1">How I like it...</h2>
<p>As I'm a freelance front-end developer that codes by candlelight I'm sure you can understand I don't work (well, not yet) on too many really big projects I generally think out most of my designs rather than initially draw a wireframe / open up photoshop. Doing this I tend to 'think' how the design would look on my iPhone and my iPad and my MacBook Air (yes, I use Apple products).</p>
<p>Therefore I always start with a 'boilerplate' of media queries. They're aren't a hard and fast of rules to stick to, just a starting point. Of course the first starting point when coding a design is as perfect as <a href="https://twitter.com/bryanrieger">Bryan Rieger</a> puts it</p>
<blockquote>
<p>The lack of a media query is your first media query</p>
</blockquote>
<p>So I do all of my basic stuff here, all the typography stuff, things like that before I even get to a media query. Then after that I start designing (well, coding?) with this list of <a href="http://app.kodery.com/s/1075">basic media queries</a> -</p>
<p>/* ===== == = === Base Styles === = == ===== */</p>
<p>/* ===== == = === 20em (320px) === = == ===== */</p>
<p>@media only screen and (min-width : 20em) {
}</p>
<p>/* ===== == = === 30em (480px) === = == ===== */</p>
<p>@media only screen and (min-width : 30em) {
}</p>
<p>/* ===== == = === 37.5em (600px) === = == ===== */</p>
<p>@media only screen and (min-width: 37.5em) {
}</p>
<p>/* ===== == = === 48em (768px) === = == ===== */</p>
<p>@media only screen and (min-width : 48em) {
}</p>
<p>/* ===== == = === 56.25em (900px) === = == ===== */</p>
<p>@media only screen and (min-width : 56.25em) {
}</p>
<p>/* ===== == = === 68.75em (1100px) === = == ===== */</p>
<p>@media only screen and (min-width : 68.75em) {
}</p>
<p>/* ===== == = === 81.25em (1300px) === = == ===== */</p>
<p>@media only screen and (min-width : 81.25em) {
}</p>
<h2 id="em%2C-how-many%3F" tabindex="-1">Em, How many?</h2>
<p>I lied, it's not really basic it's slightly more than that. Once I've designed (well, coded) with some or all of these breakpoints I then start getting my resizing thing down. For me that's the key bit. Not where or when you include your media query 'breakpoints' in earnest, but what goes in between.</p>
<blockquote>
<p>'Start with the small screen first, then expand until it looks like shit. Time to insert a breakpoint!'</p>
</blockquote>
<p>Although I don't follow <a href="https://twitter.com/stephenhay">Stephen Hay's</a> words to the letter, the next part along my design(coding?) process is to resize the browser until it 'looks like shit' then I'll add a breakpoint to fix it. I may even add a min-width and a max-width rule, or a max-width rule. Whatever works to make the design look nice at any viewport size, as best I can. Don't forget to test on as many devices as possible either.</p>
<p>You'll also not I'm using <a href="http://blog.cloudfour.com/the-ems-have-it-proportional-media-queries-ftw/">ems for my breakpoints</a> instead of px. This helps for users who zoom and ties your media queries more to the design than device viewport.</p>
<h2 id="but%2C-what-about-the-future%3F" tabindex="-1">But, what about the future?</h2>
<p>How long in the future are we going? Well as phones are being released (well, Android OS'd ones) faster than you can say Jack Robinson so are list of possible viewport sizes we're going to have to deal with but there are still going to be more popular devices that'll (I'm in) know doubt will keep to roughly the same pixel screen resolutions they do at the moment, if not a few years to come (in the future).</p>
<h2 id="content-first%3F" tabindex="-1">Content first?</h2>
<p>Well, content blocks first. My expectations of a client to deliver everything I need before I start are unfortunately not going to be delivered soon. The project I was working on January - March (sshhhh, we're still working on it) this year had content that would have been provided by it's users so I had to work with what the content could be expected to look like and where it would go etc. This worked, it worked just fine. I'd love every word to be presented, that's not going to happen, nor should it. The web is a breathing beast, so is it's content.</p>
<h2 id="my-point." tabindex="-1">My Point.</h2>
<p>I don't think that having a set of 'common' media queries harms your desiging of a site as long as you resize that bad boy and fix anything that looks shit. Like all things I do when I'm coding though, this idea is subject to change.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Adding a class with JavaScript, The Results</title>
      <link href="https://www.alwaystwisted.com/articles/adding-a-class-with-javascript-the-results.html"/>
      <updated>2012-04-27T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/adding-a-class-with-javascript-the-results.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/1335556810untitled1-ck.jpg" alt="I god damn changed my mind, yes I did." loading="lazy" decoding="async"></p>
<p>Yesterday I wrote about how I'm <a href="http://alwaystwisted.com/post.php?s=2012-04-26-nojs-no-i-like-hasjs">adding a HasJS class to the HTML</a> element in my designs rather than swapping out a no-js class or removing a no-js class.</p>
<p>i'd originally thought that the best way (well the only way I originally thought of) was to add -</p>
<p><code>$('html').addClass('hasJS');</code></p>
<p>to my script.js of my (work in progress) personal, personable boilerplate.</p>
<p>Soon after realising that blogpost to the world <a href="http://allmarkedup.com/">Mark Perkins</a> added a comment saying that add this -</p>
<p><script>document.getElementsByTagName('html')[0].className += ' hasJS';</script></p>
<p>added in the head would be a better/quicker way of doing it. I also had a couple of comments via the twitters saying this too.</p>
<h2 id="testing%2C-testing...1%2C-2%2C-3" tabindex="-1">Testing, Testing...1, 2, 3</h2>
<p>So I decided today that what better way to spend a Friday evening that test those two bits of code with JSPerf. Now, in all honesty, I don't know what I'm doing. But, Sshhhh!!!. So I managed to find a test that already tested the performance for JavaScript to add a class with jQuery and 'Modern Javascript'. I thought this was perfect and also added the code that Mark offered and ran some tests.</p>
<h2 id="whaaaatt%3F%3F%3F" tabindex="-1">Whaaaatt???</h2>
<p>Whilst I was testing all the browsers I've got on my MBA I thought it best to open up my Parallels VMWare and run it in IE9 (to start). Here's where I hit a problem with one of the tests. So I thought I'd do what I often do <a href="http://twitter.com/jack_franklin">'Ask Jack'</a>.</p>
<p>He pointed to a <a href="https://developer.mozilla.org/en/DOM/element.classList">Mozilla Dev page</a> which shows that IE (until v10) doesn't support -</p>
<p>classList</p>
<p>On that page is a nice <a href="https://github.com/eligrey/classList.js/blob/master/classList.js">polyfill for IE8 and up</a> so I 'shoved' that into that test code and re-ran the tests.</p>
<h2 id="near-the-finish-line..." tabindex="-1">Near the finish line...</h2>
<p>Here's the <a href="http://jsperf.com/modern-js-vs-jquery-add-class/3">results</a> for the test I re-ran with the polyfill included.</p>
<p><img src="/images/articles/1335556227screenshot20120427at20.47.01-ck.png" alt="" loading="lazy" decoding="async"></p>
<p>As you can see the modern JS approach is quickest by miles. So I've decided (subject to change) that I'm now going to include -</p>
<p>document.querySelector('html').classList.add('js');</p>
<p>into the HEAD of my personal, personable boilerplate.</p>
<h2 id="just-one-more-thing" tabindex="-1">Just one more thing</h2>
<p>You may noticed that I've also ditched .hasJS for just .js for my class name. This was spurred on from a brief couple of tweets with <a href="http://twitter.com/mattwilcox">Matt Wilcox</a> that made me decide that losing those three charecters will shave at least a little off my stylesheet file size. Every little helps and all that. That's about it for this post. You know, tomorrow is a different day. I may change my mind all over again. I'm currently trying to work out how to conditionally load the polyfill if <code>classList</code> is not supported. Until then, good 'morrow</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>no-js? No, I like hasJS</title>
      <link href="https://www.alwaystwisted.com/articles/no-js-no-i-like-hasjs.html"/>
      <updated>2012-04-26T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/no-js-no-i-like-hasjs.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/untitled1-ck.jpg" alt="my boilerplate, made by me" loading="lazy" decoding="async"></p>
<p>I last looked at my 'boilerplate' in January. It was before a long 120 hours of front end development for a product myself and my now co-founders are still working on. But I digress.</p>
<p>What I did at the time was download both the <a href="http://html5boilerplate.com/">HTML5 Boilerplate</a> and Andy Clarke's <a href="http://stuffandnonsense.co.uk/projects/320andup/">320&amp;Up</a> Framework. I went through every line of code, deleting bits I didn't want to include by default and changing other bits to more suit my asthetic needs (and change hot pink to a dark blue).</p>
<p>After doing this whilst coding the sight I wanted to progressively enhance the design (as you do) so that it'd work great with JavaScript (well jQuery) off or on.</p>
<p>I initially left the no-js tag in the html class in the html template and decided to swap it out and replace it with hasJS if the user has JavaScript enabled. After demoing my code via the twitters someone asked why I'm swapping out no-js and replacing it. After this I chose to only add the hasJS tag to the HTML document if the user has JavaScript enabled.</p>
<p>This way, for me I'm progressively enhancing what I'm doing. The code is all lovely and clean and if parts of the design make use of jQuery I only have to add a .hasJS to that particular div/article/nav/ul/whatever in the CSS. It works for me, it may not work for you. Like all things, we all have a preference to what ever options there are.</p>
<p>So here's what I do -</p>
<p>In my scripts.js file I now have this at the top of the code -</p>
<p>$('html').addClass('hasJS');</p>
<p>Then whenever I want some of my fantastically clean CSS to be changed because I'm now doing something a little different because of the jQuery I'd do this -</p>
<p>article { background-color: red; }</p>
<p>.hasJS article { background-color: pink; }</p>
<p>This way when the jQuery kicks into play it'll change the background-color, when it's not working it'll stay red.</p>
<p>Note, I don't use Modernizr, so any benefit the no-js class had with this is lost on me. This is how I do it and it goes with my belief that my boilerplate is mine, it's for me, it helps me how I work. It may be taking bits from here and there but it's be refactored to how I want it. This is just one of the decisions I've made in making my boilerplate. I hope to blog more on anything else that I've changed/edited/deleted or added to my boilerplate soon too.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Listen, everyday...</title>
      <link href="https://www.alwaystwisted.com/articles/listen-everyday.html"/>
      <updated>2012-04-07T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/listen-everyday.html</id>
      <content type="html">
        <![CDATA[
        <p>Web design, currently, is not my fulltime gig. I'm a project technician for a conference set design, construction and installation company. I live about 12 miles from work. Which gives me plenty of time during the day to listen to some podcasts.</p>
<p>There's fantastically been a glut of new podcasts as well as some that are little older because they're getting better and better. So I'm making a little list. Below are some new podcasts that I listen to regularly.</p>
<h3 id="let's-make-mistakes" tabindex="-1"><a href="http://muleradio.net/mistakes/">Let's Make Mistakes</a></h3>
<p>As of writing this blog, this podcast from <a href="https://twitter.com/mike_ftw">Mike Monteiro</a> and <a href="https://twitter.com/slowtext">Katie Gillum</a> of <a href="http://muledesign.com/">Mule Design</a> is in it's 40th episode. Amongst the fantastic banter between Katie and Mike they discuss a variety of design topics. A stalwart go to if I want to listen to something.</p>
<h3 id="the-industry-podcast" tabindex="-1"><a href="http://theindustry.cc/category/podcast/">The Industry Podcast</a></h3>
<p>Only coming into episode 3 of a nice little podcast discussing web design and what's been 'going on' with, so far, a special guest each week.  One to definitely add to your itunes podcast list.</p>
<h3 id="shoptalk-show" tabindex="-1"><a href="http://shoptalkshow.com/">Shoptalk Show</a></h3>
<p>From <a href="http://twitter.com/chriscoyier">Chris Coyier</a> and <a href="http://daverupert.com/">Dave Rupert.</a> A weekly show that's just coming into double figures. A great chat with other indusry folks answering listener questions. Usually discussiing one 'topic' a week depending on the guest.</p>
<h3 id="the-east-wing" tabindex="-1"><a href="http://theeastwing.net/">The East Wing</a></h3>
<p>Another new weekly podcast, this time bought to you by <a href="http://timothybsmith.com/">Tim Smith</a>. A weekly 'interview' style show discussing the guests career, thoughts on the industry and things that have happened that week.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>My Favourite 5 Books</title>
      <link href="https://www.alwaystwisted.com/articles/my-favourite-5-books.html"/>
      <updated>2012-02-16T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/my-favourite-5-books.html</id>
      <content type="html">
        <![CDATA[
        <p>Like <a href="http://www.mikestreety.co.uk/2012/02/books-a-smashing-story/">@mikestreety</a>, I love the printed form factor of books. I've recently gone a little mental and purchased a whole slew of books (12 at the last count). Here's my current top 5.</p>
<ol>
<li><a href="http://shop.oreilly.com/product/0636920018100.do">Head First Mobile Web</a> [O'Rielly] {Mobile, CSS, HTML, JavaScript} - A great book to help you understand how we can design (well dev) for mobile devie and what pitfalls you will encounter. It's a great little (well  huge) book you can dip into or read from cover to cover.</li>
<li><a href="http://smacss.com/">SMACSS</a> [@snooka] {CSS} - This books gives insight to a system on how you can write your CSS to make a more manageable easy to use for your sites. I just still need to implement it. I cheated here as it's an eBook.</li>
<li><a href="http://www.abookapart.com/products/mobile-first">Mobile First</a> [A Book Apart] {Mobile} - A Book Apart make great little books. This from <a href="http://twitter.com/lukew">@lukew</a> is a must read for the modern web designer.</li>
<li><a href="http://shop.oreilly.com/product/9780596802455.do">CSS: The Missing Manual</a> [O'Rielly] {CSS} - For someone that took a haitus just as CSS was being developed in the browser wars of the 1990s when I came back to web design I needed to get some skills. This book was perfect for that. So easily readable and informative.</li>
<li><a href="http://www.sitepoint.com/books/mobile1/">Build Mobile websites and apps for smart devices</a> [sitepoint] {HTML, CSS, Design} - notice a theme? This has been a real help in creating the markup, layout and other code for a current project.</li>
</ol>
<p>As Iv'e got to number 5, loads of other books in my collection have come to mind. Both books from <a href="http://zomigi.com/">Zoe</a>, <a href="http://www.abookapart.com/products/responsive-web-design">Ethan's</a> book to name a few.</p>
<p>What's your top 5? Create a blog post and add it to the comments of Mike's <a href="http://www.mikestreety.co.uk/2012/02/books-a-smashing-story/">original post</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A green light for productivity</title>
      <link href="https://www.alwaystwisted.com/articles/a-green-light-for-productivity.html"/>
      <updated>2012-02-05T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-green-light-for-productivity.html</id>
      <content type="html">
        <![CDATA[
        <p>I don't really DO todo lists. I love the idea of writing everything down that needs to be done and then ticking them off or putting a line through them when they're complete. But, when it comes to it. I'd rather spend that time on actually 'doing the work'.</p>
<p>I've generally kept mental todo list of everything that needs doing on the project that I'm working on but my current client asked for a list of what is left todo this weekend so I obliged.</p>
<p>In doing so I've created a basic little .doc file in pages. Now I happened upon an idea whilst typng this out.</p>
<p>Hopefully we all know about the red, amber and green traffic light system? Well that's what I'm applying to this clients todo list.</p>
<p>Basically everything that's entered is intitally coloured RED. When I make a start on something it gets changed and moved to AMBER. If it gets completed then it moves to GREEN. If it doesn't get completed additional notes are made as to what's left to do.</p>
<p>I'm in no doubt this is being employed by others. But I thought I'd add my little productivity finding with you on a dreary Sunday morning.</p>
<p>As for keep my todo list in my head. It'll still be there but I'll also be keeping this traffic light idea running too.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>An issue for &quot;one web&quot;</title>
      <link href="https://www.alwaystwisted.com/articles/an-issue-for-one-web.html"/>
      <updated>2012-02-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/an-issue-for-one-web.html</id>
      <content type="html">
        <![CDATA[
        <p>EDIT: This was originally titled 'an issue for responsive web design'. Thanks to <a href="http://twitter.com/faxtion">@faxtion</a> for pointing out that it was a crappy title.</p>
<p>Ok. This blog post may be brief. It'll no doubt be quite rambling. Let's face it, I'm from the West Country.</p>
<p>I'm currently working on a super exciting front-end project with a client who is all for the exciting new stuff of <a href="http://www.abookapart.com/products/responsive-web-design">responsive web design</a> and <a href="http://www.abookapart.com/products/mobile-first">mobile first</a>. It's brilliant, I'm super excited about what I'm working on and think it'll be aces.</p>
<p>You see I'm rambling.</p>
<h2 id="an-elephant%3F" tabindex="-1">An Elephant?</h2>
<p><img src="/images/articles/elephantintheroom-ck.png" alt="an elephant in the room" loading="lazy" decoding="async"></p>
<p>The possible problem arose today. We were discussing file uploads and all the fun that entails when I found out about a little problem with iOS.</p>
<p>Mobile Safari (as of writing) <a href="http://developer.apple.com/library/IOs/#documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html">does not support file upload</a>. So, that's quite a big problem there. You can build a fantastic website/app/juggernaut/sweet potato but you won't be able to upload anything to it from an iOS device. I think that's kind of a big deal.</p>
<p>I did a little searching on the tubes and found a little solution - <a href="http://code.google.com/p/iphone-photo-picker/">iPhone Photo Picker</a>. Admitedly as of writing this quick brain fart. I haven't looked into it with any real depth.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A LESS approach to &quot;Mobile First&quot; CSS &amp; supporting older IE browsers</title>
      <link href="https://www.alwaystwisted.com/articles/a-less-approach-to-mobile-first-css-supporting-older-ie-browsers.html"/>
      <updated>2011-12-01T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-less-approach-to-mobile-first-css-supporting-older-ie-browsers.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="update-10%2F01%2F12" tabindex="-1">Update 10/01/12</h2>
<p><a href="http://www.twitter.com/cloudhead">Alexis</a> has just tweeted with the release of <a href="https://gist.github.com/1591794">LESS 1.2.0</a> which he says now supports the first example in this blogpost. This is excellent news. As of writing this update the LESS CSS compiler has not updated yet, but give it a few days.</p>
<p><a href="http://twitter.com/necolas">Nicolas Gallagher</a> has recently written a <a href="http://nicolasgallagher.com/mobile-first-css-sass-and-ie/">fantastic post</a> about using SASS to aid you in giving legacy IE browsers a 'desktop' design whilst alse have a 'mobile first' approach in your stylesheets.</p>
<p>I don't like SASS, I prefer LESS. SASS to me is full of <a href="http://twitter.com/#!/StuRobson/status/118756553166823424">mirth</a>.</p>
<p>I set about creating myself a little framework of default files a while back that would use the LESS.app to compile my CSS before it's uploaded to the server.</p>
<p>(note: before we go any further, these following examples were tested using the latest version of the LESS.app)</p>
<h2 id="purely-fictional..." tabindex="-1">Purely Fictional...</h2>
<p>This is how I'd want it to work. It <a href="https://github.com/cloudhead/less.js/issues/122">currently doesn't</a> but hopefully will be sorted out soon...</p>
<p>I prefer the seperate stylesheets for seperate media queries approach and with LESS you can compile all of these into one CSS file for you site. This way you have a nice working enviroment with defined LESS files for defined breakpoints.</p>
<p>Although every project is different this would be my default list of LESS files -</p>
<ul>
<li>default.LESS</li>
<li>320.LESS</li>
<li>480.LESS</li>
<li>768.LESS</li>
<li>960.LESS</li>
<li>1200.LESS</li>
</ul>
<p>I also have a LESS file which I call styles.LESS which looks like this -</p>
<p>/* styles.css */</p>
<p>@import 'default';
@media (min-width:320px) {
@import '320';
}
@media (min-width:480px) {</p>
<p>What this does is pretty simple, using the LESS.app it takes the .LESS files in the list and compiles them into this CSS syntax in a file called styles.css -</p>
<p>@media (min-width:320px) { }
@media (min-width:480px) { }
@media (min-width:768px) { }
@media (min-width:960px) { }
@media (min-width:1200px) { }</p>
<p>Now if you're wanting to give older browsers (Internet Explorer 6/7/8) a single stylesheet that would give the 'desktop' design like Nicolas' post describes then you would have another LESS file called ie.LESS which would look like this -</p>
<p>/* ie.css */
@import 'default';
@import '320';
@import '480';
@import '768';
@import '960';</p>
<p>This again is pretty simple. Using the LESS.app it would put all of your sites styles in file called ie.css in the order of 'little to large' so that it would cascade to show your legacy browser that 'desktop' design.</p>
<p>As Nicolas points out at the bottom of his post, to include this into your HTML so that legacy IE browsers would use the ie.css you would put this in the <HEAD> of your markup -</p>
<p><!--[if (lt IE 9) & (!IEMobile)]>
    <link rel='stylesheet' href='/css/ie.css'>
    <![endif]--></p>
<h2 id="so%2C-what-now%3F" tabindex="-1">So, what now?</h2>
<p>Althought that currently does not work with LESS there are a couple of ways to get it to work.</p>
<p>If we keep the original style.LESS as this</p>
<p>/* styles.css */</p>
<p>@import 'default';
@media (min-width:320px) {
@import '320';
}
@media (min-width:480px) {</p>
<p>in the individual corresponding LESS file you would have for example this -</p>
<p>@media (min-width:320px) {
/* styles goes here */
}</p>
<p>Then when you save out your styles.LESS to CSS it will included all the CSS3 Media Queries with the styles within.</p>
<h2 id="that's-nasty!" tabindex="-1">That's Nasty!</h2>
<p>Yep, that's ok unless you wanted to save out a ie.css file too. Using the same approach of @import-ing the .LESS files and compiling them into a single ie.CSS file you would still get -</p>
<p>@media (min-width:320px) {
/* styles goes here */
}</p>
<p>That'd make your ie.CSS file pretty disgusting to look at and read through for yourself let alone anyone else looking at your code.</p>
<h2 id="well%2C-what-then%3F" tabindex="-1">Well, What then?</h2>
<p>There is a solution (of sorts) that would give you a styles.CSS file including all your CSS3 media queries and another stylesheet with the code in a cascading order without the media query syntax. It's a little bit more complex but once it's setup it can work in every site you create from then on.</p>
<p>First in your .LESS files that are specific to a break point in your responsive design, for example 768.LESS, include this code -</p>
<p>.max-width-768() {
/* style goes here */
}</p>
<p>Once you have populated your .LESS files with such code (for example files for 320, 480, 768, 960 and 1200 break points). You would then need to have your styles.LESS file looking like this -</p>
<p>/* styles.css */</p>
<p>@import '320.less';
@media (max-width: 320px) {
.max-width-320();
}
@import '480.less';
@media (max-width: 480px) {
.max-width-480();
}
@import '768.less';
@media (max-width: 768px) {
.max-width-768();
}
@import '960.less';
@media (max-width: 960px) {
.max-width-960();
}
@import '1200.less';
@media (max-width: 1200px) {
.max-width-1200();
}</p>
<p>Now you've done that you would want to create your single stylesheet for Internet Explorer. This is done as in the fictional bit of code at the top of the post. Like this -</p>
<p>/* ie.css */
@import 'default';
@import '320';
@import '480';
@import '768';
@import '960';</p>
<p>You'd then add this bit of code to so that it is picked up by older versions of Internet Explorer -</p>
<p><!--[if (lt IE 9) & (!IEMobile)]>
    <link rel='stylesheet' href='/css/ie.css'>
    <![endif]--></p>
<p>There we have it. A workable way of making  'Mobile First' CSS &amp; supporting older IE browsers using LESS.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Decisions, decisions, decisions</title>
      <link href="https://www.alwaystwisted.com/articles/decisions-decisions-decisions.html"/>
      <updated>2011-11-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/decisions-decisions-decisions.html</id>
      <content type="html">
        <![CDATA[
        <p>So, you're about to go live. You're just dotting that last lower case j on the site and you hit the 'go' button.</p>
<p>That new site you've been working on is live. It's out there on the information super highway. You're full of smiles. You think it looks great, you know it works fantastic and the cleanliness of your code is something to die for.</p>
<h3 id="but." tabindex="-1">But.</h3>
<p>You want to tell the world. Gone are the days of adding it to forums or even email people you know. Just one tweet and you can reach all your followers and more.</p>
<h3 id="what-next%3F" tabindex="-1">What Next?</h3>
<p>Everyone's seen your tweet and are looking at your site in their preferred browser. Then they start to resize the browser.</p>
<h3 id="'oh%2C-isn't-it-responsive%3F'" tabindex="-1">'Oh, isn't it responsive?'</h3>
<p>It may be, it may not be. It still a lovely design but with the poster child of design approachs being that fluid grid that'll resize to your mobile telephone's viewport most people expect it to resize.</p>
<p>If it doesn't a plethora of tweets as to the why and where fors abound. You're inundated.</p>
<h3 id="'why-do-i-have-to-explain-myself%3F'" tabindex="-1">'Why do I have to explain myself?'</h3>
<p>You don't. Plain and simple. But, I feel, that if you can you must write a little blog post explaining the business decision as to how you got to the site as it is live on the tubes.</p>
<h3 id="business-decisions" tabindex="-1">Business Decisions</h3>
<p>Time is money (or <a href="http://youtu.be/q8mgMXmsxlo">mime is money</a>). There are reasons that a site is how it is beyond how it looks. If we blog, just a little, on how we came to what we've done we would all get a better understanding of this forever growing industry and hopefully calm the 'But it's not…' tweets.</p>
<h3 id="it's-all-i-ask" tabindex="-1">It's all I ask</h3>
<p>So, next time you release that project you've been burning the midnight candle for. Just 'do' a quick blog post as to why, why and why.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>It Depends...</title>
      <link href="https://www.alwaystwisted.com/articles/it-depends.html"/>
      <updated>2011-11-13T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/it-depends.html</id>
      <content type="html">
        <![CDATA[
        <h2 id="an-introduction..." tabindex="-1">An Introduction...</h2>
<p>Since Ethan Marcotte's <a href="http://www.alistapart.com/articles/responsive-web-design/">seminal peice</a> on responsive web design we as an industry have really been talking/blogging about nothing else but.</p>
<p>That's a good thing. A great thing in fact. A majority of this industry have taken Ethan's idea for how to approach modern web design and ran with it. Some of us still don't think it's a 'trend' that'll catch on. Sure, like all things, in 5 years down the line we could be thinking 'why we're we wasting our time?'. I very much doubt that.</p>
<p>Another thought is that Responsive Web Design won't work for every project. This is true in part I feel.</p>
<p>Let's face it every project is different. Your next site build could be for the new restaurant that's opened up, a solo musicians blog or an online store selling every crayon imaginable. Could they all work with a responsive web designers approach? Probably but possibly not.</p>
<p>This is pretty much mentioned in Ethan's book. You've got that right? Read it yes? Good.</p>
<p>In the last chapter Ethan discusses the Johnny Ball (who, what, where, when, how?) of Responsive Web Design. In some cases RWD may not be the answer. I think regardless of that initial decision to use a responsive approach you should start out with at least part of the approach. Because. It may 'depend' now but down the timeline of the project something may change. If you start out with a fluid grid at least it'll help stop you having to shoehorn the techniques in at a later date. It's not much effort figuring out your pixels, your percentages and your ems and emlpoying them in your CSS.</p>
<p>If you think it is. Then you're just plain lazy.</p>
<p>Doing this at the start also allows you to 'turn it off'. You can set a media query in such a way that the site won't resize in the browser. It's a couple of lines. It's not much work.</p>
<p>If you think it is. Then you're just plain lazy.</p>
<h2 id="an-aside." tabindex="-1">An aside.</h2>
<p>Responsive Web Design is not the whole picture. It's only a part of the puzzle there's lots more 'stuff' to consider. Context, Content, Connection Speeds, Location. All of these things should be thought of with your design first.</p>
<p>This is why you shouldn't just be a web designer. You shouldn't just start being a Responsive web designer. You should start being a user centric, content first, context aware, mobile first, responsive web designer.</p>
<p>As ever, someone else has put this down in better words than I can muster. Check out @lukew's post on <a href="http://www.lukew.com/ff/entry.asp?1436">Multi-Device Web Design</a> for a more structure point of view.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>I am realigning, redesigning, changing &amp; growing</title>
      <link href="https://www.alwaystwisted.com/articles/i-am-realigning-redesigning-changing-growing.html"/>
      <updated>2011-07-21T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/i-am-realigning-redesigning-changing-growing.html</id>
      <content type="html">
        <![CDATA[
        <p>Just thought I'd throw a quick post up to let you all know (well all 3 of you) that I'm in the (lengthy) process of redesigning this site.</p>
<p>Of course, when I say redesign I mean realign. Well both actually. I created this rather hurridly over Christmas &amp; New Year 2010 and wanted to have so much 'fun' stuff on it I rushed it out the door before everything was ready (backstage area and the daily bit). So this time around I'm taking my time. I'm not rushing. If you know me, you know I never intentially rush (<a href="http://www.youtube.com/watch?v=HbR7axof1wk">'Life moves pretty fast. If you don't stop and look around once in a while, you could miss it.'</a>).</p>
<p>So what is going to happen?</p>
<p>Well I'm going to add an actual porftolio to the site (including my services) so that I can use this site to 'show off' (and hopefully get) client work. I did have a fantastic domain (<a href="http://www.handcodedmedia.com">www.handcodedmedia.com</a>) but as I'm struggling to have this the way I want it as a blog I think that trying to create an additional 'services' site would make <a href="http://en.wikipedia.org/wiki/All_work_and_no_play_makes_Jack_a_dull_boy">Jack a dull boy</a>.</p>
<p>I'm hoping to have a daily post. Just to spill some of the minutiae of my day with you all.</p>
<p>I'm hoping to create a 'labs' (previously underdeveloped backstage) area where I can just post quick ideas without the need for a full blog post.</p>
<p>I'll contiue writing this blog. Albeit more regularly. I'm also going to add the abilty to add comments to the blog (on my chosing). I did write previously that <a href="http://alwaystwisted.com/post.php?s=2011-02-24-why-have-i-not-got-comments-on">I don't want comments</a> but I feel that train of though was wrong. Not allowing people to comment on a post will invariably get them tweetin about their agreement or disagreement and thoughts which as we know is limited to 140 charecters and conversations get borken easily. So comments are good. Comments will be on :D</p>
<p>I'll add a portfolio, services and contact page. I'll 're-jig' the about page so it's less '<a href="http://www.thefreedictionary.com/wordy">wordy</a>' and that should pretty much be about it.</p>
<h2 id="responsive-web-designing" tabindex="-1">Responsive Web Designing</h2>
<p>If you do look at this on your 'mobile' device or tablet you'll see the responsive web design is a bit screwy. This was a slight afterthought and before mobile first went stellar. I have more users on iPads and iPhone than I do on IE6 + 7 combined.</p>
<p>My redesign will be built from the ground up. Using a bit of the <a href="http://html5boilerplate.com/">HTML5 Boilerplate</a>, a bit of the <a href="http://www.getskeleton.com/">Skeleton framework</a>, a bit of <a href="http://stuffandnonsense.co.uk/projects/320andup/">320 and up</a> so a bit of this that <a href="http://www.youtube.com/watch?v=tScm-eZInBE">and the other</a>.</p>
<p>I'm hoping to have this all done in time for the <a href="http://www.updateconf.com">UpdateConf</a> that I'm attending. Along with fresh business cards too :)</p>
<p>Until then, I may post. I may not. I had a great time watching some fantastic speakers at this years <a href="http://environmentsforhumans.com/2011/css-summit/">CSS Summit</a> and have several ideas and comments I want to share. So you never know. ;)</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>All of sudden I lost 14 inches</title>
      <link href="https://www.alwaystwisted.com/articles/all-of-sudden-i-lost-14-inches.html"/>
      <updated>2011-07-04T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/all-of-sudden-i-lost-14-inches.html</id>
      <content type="html">
        <![CDATA[
        <p>If you follow me on <a href="http://www.twitter.com/sturobson">twitter</a> and why wouldn't you? You may know that I've sold my 27' iMac. It took a while. I decided to sell it a little bit too late (just days after they updated the <a href="http://www.apple.com/thunderbolt/">whole range</a> again). So I was stuck with it on eBay for 30 days trying to sell it. Eventually I found a buyer. Or they found me.</p>
<p>One morning I woke to a message from <a href="http://message.uk.com/">Message</a> saying they're interesting in buying it from me. With a few quick tweets to them and various people asking for advice it wasn't long before the deal was struck.</p>
<p>A courier was to collect my iMac from me on Thursday and once delivered funds would be transferred into my account. That was a bit of a pain. I was worried that I'd be without a computer for the weekend. I panicked. After a couple more tweets to some fine fellows I decided to use my just cleared pay cheque to buy a MacBook Pro.</p>
<p>You may think I'm a bit mad. I've gone from a 27' massive <a href="http://www.apple.com/imac/">iMac</a> screen down to a 'tiny' 13' <a href="http://www.apple.com/macbookpro/">MacBook Pro</a>. Why? There's a couple of reasons.</p>
<ol>
<li>The iMac was a desktop. As I only use the computer in the evening as my web design shenanigans (for the moment) is purely 'part time'. I just couldn't get used to having to sit in the office (dining room). Whilst my partner was in the sitting room. I found myself using my iMac less and less.</li>
<li>27' is <a href="http://de.acidcow.com/pics/20100621/how_big_17.jpg">massive</a>. I found it was too big for me. I couldn't really concentrate as there were so many pixels to look at. The 13' is perfect. I've only got a small screen to look at. I can focus much better.</li>
</ol>
<p>So I got my MacBook Pro. A 13' 2011 model, 2.3Ghz i5 with 4GB of RAM and a 320GB 5200rpm hard drive. On the afternoon I ordered it <a href="http://www.twitter.com/lloydi">@lloydi</a> was talking about a hard drive he's got in his 15' 2008 MacBook Pro. A <a href="http://www.seagate.com/www/en-gb/products/laptops/laptop-hdd/">Seagate Momentus XT Hybrid</a>. It's got a 500GB 7200rpm hard drive AND a 4GB SSD in there too. The SSD basically helps your most used programmes open quicker. I was sold in seconds and ordered it after having the MacBook for only 4 days. It makes the laptop loads from cold quicker too. Whilst I was in a spending mood I also ordered 8GB of RAM too.</p>
<p>It all arrived, I installed it in moments (well, after a Time Machine backup).</p>
<p>It's one quick machine now.</p>
<p>I'm currently waiting 20 seconds when I boot up. Which is great. Photoshop, Coda, Chrome, Kiwi and Itunes load in a snap. No waiting. NONE.</p>
<p>Total cost for the upgrade £150 (ish). The MacBook Pro, being a refurb model, was £849 instead of the usual £999 rrp. A grand well spent.</p>
<p>I think this'll last me for some years to come. I can't see me every going back to a desktop. Well, Never say never.</p>
<p>But there must be some problems right?</p>
<p>Yes, of course. I've been 'used to' my iMac with a magic mouse and a wireless keyboard. All of a sudden I have to use a trackpad. My <a href="http://en.wikipedia.org/wiki/Muscle_memory">muscle memory</a> needed 'retraining' but that's done now.  The other thing is the screen (under certain circumstances). It's a glossy screen. So depending where I'm sitting in the house. I sometimes don't get the best view of the screen because of all of the glare and reflections. But that's ok. I can sit in another chair.</p>
<p>And that's about it. I've got a new toy. I'm 'blogging' again. I'm trying to do some more work. I've got several projects 'on the go' so being able to use this bad boy wherever I am makes it easier than it ever used to be.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Last Weeks Hot Topics (03/07/11)</title>
      <link href="https://www.alwaystwisted.com/articles/last-weeks-hot-topics-030711.html"/>
      <updated>2011-07-03T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/last-weeks-hot-topics-030711.html</id>
      <content type="html">
        <![CDATA[
        <p>Here's a quick selection from this weeks blog posts I've found interesting from my RSS feed.</p>
<p>I hope you do too.</p>
<p>So, sit back, Relax!. Have a cup of Joe.</p>
<p>Enjoy.</p>
<p>If you've got any suggestions or you've got a blog I should add to my list of many then catch me on <a href="http://www.twitter.com/sturobson">twitter</a></p>
<p><a href="http://feedproxy.google.com/~r/veerlesblog/~3/ZI64WcuxHjs/">CSS3 Linear Gradients</a><br>
Good write-up on CSS3 Linear Gradients + link to useful tool....=</p>
<p><a href="http://tympanus.net/codrops/2011/07/03/sliding-background-image-menu/">Sliding Background Image Menu with jQuery</a><br>
View demo Download source Today we want to share another jQuery menu with you. This menu will have several panels, each one corresponding to a different background image that will show on all panels w...</p>
<p><a href="http://www.webresourcesdepot.com/leanmodal-a-micro-jquery-modal-plugin/">leanModal – A Micro jQuery Modal Plugin</a><br>
Advertise here with BSA leanModal is a lightweight jQuery plugin for displaying modal boxes with minimum effort. The plugin doesnt use any images and a very good solution for for displaying anything...</p>
<p><a href="http://giraffeforum.com/wordpress/2011/07/03/eliminate-task-duplicates/">Eliminate task duplicates</a><br>
How many unique tasks are there in the following list? • Book an appointment online • Appointment reminders • Let me book an appointment • Make an appointment • Request an appointment Yes, two. One ta...</p>
<p><a href="http://feedproxy.google.com/~r/ProbloggerHelpingBloggersEarnMoney/~3/O112kYlFn2I/">Are You a Creative Blogger?</a><br>
This guest post is by Chris Kahler of <a href="http://bloggeritus.com/">bloggeritus.com</a> . It doesn’t take a genius to stroll around cyberspace and quickly find that the World Wide Web is littered with junk. There is a lot of “stuff” ...</p>
<p><a href="http://feedproxy.google.com/~r/CreativeDesign/~3/wKD1LangDSU/">Aesop on giving critiques</a><br>
It’s easy to speak negatively about the work of others, but never forget the quality of your own. The Two Bags According to ancient lore, every man is born into the world with two bags suspended from ...</p>
<p><a href="http://www.readactor.com/premium-wordpress-theme/rockwell-portfolio-blog-wordpress-theme/">RockWell – Portfolio &amp; Blog WordPress Theme</a><br>
Click on image for demo! Features 43 Unique ‘Category’ Templates – could be used as a Blog, Portfolio or just about anything you want 20 Unique ‘Single Post’ Templates – could be used as a Blog, Portf...</p>
<p><a href="http://feedproxy.google.com/~r/tripwiremagazine/~3/_NlqLhVWJSk/beautiful-yellow-website-designs.html">40 Examples of Beautiful Yellow Website Designs</a><br>
Yellow is the color evoked by light that stimulates both the long and medium wavelength cone cells of the retina about equally, with no significant stimulation of the short-wave cone cells . A Light w...</p>
<p><a href="http://rel.ly/2011/07/01/wavingnotdrowning/">Waving not drowning: or how I gave in and learned to love the content strategy flood.</a><br>
Here’s a sobering admission. If the body of knowledge of content strategy is an ocean, I’m currently about ten foot out from</p>
<p><a href="http://feedproxy.google.com/~r/LostAndTaken/~3/ZhKjGBaq9sY/19-free-block-print-textures.html">19 Free Block Print Textures</a><br>
I've got a cool treat for you guys today. L&amp;T reader Derek Oscarson has provided this set of 19 free letterpress and block print textures that you can use freely in your design projects (personal &amp;co...</p>
<p><a href="http://freelancefolder.com/50-questions-to-ask-yourself-after-6-months-of-freelancing/">50 Questions to Ask Yourself after 6 Months of Freelancing</a><br>
tweetmeme_source = 'FreelanceFolder'; It’s a well-known fact that most freelancers don’t get performance reviews. For one thing, most private clients don’t think of it. Even on bidding sites where...</p>
<p><a href="http://feedproxy.google.com/~r/gavinelliottblog/~3/BJNdNZJqA84/">The healthy future of the web industry maybe short-lived</a><br>
Just three weeks ago I was stood on a stage in Vancouver, Canada. One of the first lines I said to the audience was, “Our industry is in one of the most exciting times of its life.”I meant every singl...</p>
<p><a href="http://feedproxy.google.com/~r/Webappers/~3/euLZtj-bc-g/">CSS3 Transitions with Custom Easing Functions</a><br>
CSS3 transitions are easy to implement, more performant than the setTimeout based alternative &amp;because of this work really well on mobile devices. However, it is not as flexible as the Javascript alte...</p>
<p><a href="http://acrisdesign.com/2011/06/fabric-texture-in-web-design/">Fabric Texture In Web Design</a><br>
In this showcase we have featured some of beautiful and creative fabric textured web designs for inspiration which inspired you how to use a fabric textures in your own web design. We also included so...</p>
<p><a href="http:/?p=5261#comments">Add a Google+ Badge to Your Website</a><br>
Google’s new Google+ service is taking the development world by storm, and why shouldn’t it?  It’s minimalistic UI, use of cutting edge web techniques, and overall usability make it Google+ one of the...</p>
<p><a href="http://www.crazyleafdesign.com/blog/10-principles-of-effective-web-designing/">10 Principles Of Effective Web Designing</a><br>
Web designing is not just creating a site with colorful images. You need to follow various rules and use tools for designing a website to attract target traffic. Using website design templates has si...</p>
<p><a href="http://freelancefolder.com/7-top-freelance-survival-tips/">7 Top Freelance Survival Tips</a><br>
tweetmeme_source = 'FreelanceFolder'; These seven freelance survival tips will help to see you through the lean times -and there will be lean times, at least until you have an established, reliabl...</p>
<p><a href="http://feedproxy.google.com/~r/SixRevisions/~3/kgMVOgGzfqQ/">Things Worth Paying For as a Freelancer</a><br>
Advertise here with BSA A freelancer, like a baker, needs a few essential tools with which they create their products and use in order to offer their services. Instead of pots, mixing bowls, spoons an...</p>
<p><a href="http://www.webdesignerdepot.com/2011/06/ribbons-and-tags-in-web-design/">Ribbons and tags in web design</a><br>
Trends can be born so silently and subtly that we seldom notice them. And when you survey hundreds of websites, you often see patterns that you would otherwise miss. One such pattern is the frequent u...</p>
<p><a href="http://www.1stwebdesigner.com/design/creating-faq-tips/">5 Simple Tips for Creating an Effective FAQ Page</a><br>
A Frequently Asked Questions page is necessary if you’re selling something, providing a service, or giving information about a complex subject. It takes the guesswork away from your visitors who may h...</p>
<p><a href="http://feedproxy.google.com/~r/vitaminmasterfeed/~3/sam1EZB9iRw/">Episode #28: News Roundup and Ryan’s Weird Thing of the Week</a><br>
This week Ryan is back from his spreadsheets and talks us through the possibilities of 3D hologram websites. We also discuss using WordPress to power your newspaper , the release of GitHub for Mac ,...</p>
<p><a href="http://feedproxy.google.com/~r/webexpedition18com/~3/PHlVF5Crdxc/">You Want To Become An Effective Web Designer? Follow These Steps!</a><br>
Tweet Web designing is not just creating a site with colorful images. You need to follow various rules and use tools for designing a website to attract target traffic. Using free web site templates ha...</p>
<p><a href="http://webdesignledger.com/inspiration/typography-inspiration-20-creative-examples">Typography Inspiration: 20 Creative Examples</a><br>
Advertise here with BSA The word typography , from the greek word typos, is the art and technique of arranging type. And I have to agree that arranging typography is an art. Some designers have the r...</p>
<p><a href="http://lazyload-plugin/#comments">Introducing LazyLoad 2.0</a><br>
While improvements in browsers means more cool APIs for us to play with, it also means we need to maintain existing code.  With Firefox 4#8242s release came news that my MooTools LazyLoad plugin was ...</p>
<p><a href="http://blog.typekit.com/2011/06/29/using-typekit-fonts-in-your-own-css/">Using Typekit fonts in your own CSS</a><br>
With some of the recent improvements to our kits , Typekit is providing more tools for using fonts on the web than ever before. The options range from basic and drop-dead simple (just add fonts and s...</p>
<p><a href="http://feedproxy.google.com/~r/nettuts/~3/qmQB6KV-cDA/">Showcase of Inspiring “About Me” Pages</a><br>
Advertise here A creative about me page will attract a reader’s attention, and, more importantly, provide them with a quick sampling of what you or your company represents. Are you playful, stylish, c...</p>
<p><a href="http://feedproxy.google.com/~r/GraphicDesignBlender/~3/1DWBxDhe-EM/charge-for-your-design-time">Charging for freelance design: by the hour or per project?</a><br>
Have you ever found yourself pulling your hair out over how much to charge for a design project? It can be very frustrating and usually ends up costing you more time (and thus money) than it should. T...</p>
<p><a href="http://feeds.copyblogger.com/~r/Copyblogger/~3/7BxnSD6cwnU/">When You Absolutely, Positively Must Know if Your Content Will Rock … Do This</a><br>
Ever had a great idea, and then started to doubt yourself? Or maybe you’ve already executed on that great idea, but you’re hesitating to launch. Maybe it’s an article, or an ebook, or a completely new...</p>
<p><a href="http://www.smashingmagazine.com/2011/06/29/five-copywriting-errors-that-can-ruin-a-company-website/#comments">Five Copywriting Errors That Can Ruin A Company’s Website</a><br>
No matter how brilliant a website’s design, no matter how elegant its navigation, sooner or later visitors will decide whether to take action because of something they read . In the end, the effectiv...</p>
<p><a href="http://www.attitudedesign.co.uk/attitude-design-official-apple-iphone-app-developers/">Attitude Design Official Apple iPhone App Developers</a><br>
We’re pleased to announce that Attitude Design are now official Apple Developers. This means we can now create Apps officially under the name of Attitude Design Ltd. We have been developing apps for t...</p>
<p><a href="http://feedproxy.google.com/~r/creativeoverflowblog/~3/5w_01LlunXg/">The Mysterious Ways of Web Typography</a><br>
It has recently come to my attention that there are more honest politicians than there are web designers who understand typography. As few as that!? You cry. When I say ‘typography’here, I am not tal...</p>
<p><a href="http://feedproxy.google.com/~r/speckboy-design-magazine/~3/fF5QygpdaiU/">How to Create a Basic WordPress Theme with Gantry Framework</a><br>
Advertise here with BSA Gantry Framework is a WordPress theme framework that, unlike most of its modern counterparts, allows the user to construct a layout and color palette from within the WordPress ...</p>
<p><a href="http://feedproxy.google.com/~r/Webappers/~3/vQ2ek23yPiQ/">Share Your Code with GitHub for Mac</a><br>
GitHub for Mac has just launched recently. Now you can Clone repositories, Browse history, Commit changes, Branch code, and Share code on <a href="http://github.com/">github.com</a> as simple as possible. The sync button pushes your ...</p>
<p><a href="http://www.visualswirl.com/inspiration/best-law-firm-website-designs/">25 of the Best Law Firm Website Designs</a><br>
Attorney websites have a history of being boring and bland. Pages and pages of legal history and attorney-speak can only be spiffed up so much, right? Well it looks like some lawyers have started taki...</p>
<p><a href="http://csswizardry.com/2011/06/fluid-grid-calculator/">Fluid grid calculator</a><br>
What with Ethan’s book and A List Apart article the whole community is responsive design mad. Which is a good thing…I’ve been looking at redesigning CSS Wizardry onto a fluid grid and also adding a ...</p>
<p><a href="http://css-tricks.com/9838-techniques-for-context-specific-images/">Techniques for Context Specific Images</a><br>
One of the shortfalls of using CSS media queries as the only ingredient of a mobile solution is that the same content gets served to both desktop browsers and mobile devices (which theoretically are s...</p>
<p><a href="http://feedproxy.google.com/~r/artatm/~3/elIXLtnDDBU/">How should a web designer use the services of social media?</a><br>
Social media is the hottest topic online, but recently its importance seems to be transcending to real life as well. The great advantage of social media is that it allows people to communicate and exc...</p>
<p><a href="http://vandelaydesign.com/blog/galleries/navigation-menus/">25 Beautiful Navigation Menus</a><br>
Navigation menus are a critical part of web design because of their importance for usability and creating a position user experience. Websites with poor navigational structure or a lack of clarity in ...</p>
<p><a href="http://www.1stwebdesigner.com/css/css-counters-organize-ordered-content/">CSS Counters – The Right Way to Organize Your Ordered Content</a><br>
It is pretty common to see step-based content. Tutorials, shopping carts, FAQ’s, grandma’s recipes. You know, numbers and steps are really good to grab attention, so many writers use this....</p>
<p><a href="http://www.noupe.com/design/the-keys-to-making-fresh-forwardly-aesthetic-web-designs.html">The Keys to Making Fresh, Forwardly Aesthetic Web Designs</a><br>
Great graphics . Beautiful typography . Clean design . These are all things designers typically think of when creating stunning websites. But is it really just that combination of elements that pro...</p>
<p><a href="http://www.virtuosimedia.com/business/marketing/how-to-plan-content-marketing-strategies-for-your-website">How To Plan Content Marketing Strategies For Your Website</a><br>
Theres an old saying that goes “If you fail to plan, youre planning to fail.”To put that another way, no one ever plans to fail or do a bad job, but plenty of people plan to make a plan of any kind...</p>
<p><a href="http://feedproxy.google.com/~r/tripwiremagazine/~3/pmx3xj4wVE8/25-informative-yql-tutorials-to-get-you-started-with-yql.html">25 Informative YQL tutorials to get you started with YQL</a><br>
Yahoo! query language ( YQL ) is an SQL-like query language created by Yahoo! as part of their Developer Network. YQL is designed to retrieve and manipulate data from APIs through a single Web interfa...</p>
<p><a href="http://feedproxy.google.com/~r/TheSocialMediaChannel/~3/15x6Pndetl4/">9 ways to build an easy, engaging content strategy</a><br>
Technology and luxury: two industries that move at a fast pace, demanding constant innovation and high quality products. Luxury was slow in embracing the digital world, but has come a long way in a so...</p>
<p><a href="http://spyrestudios.com/30-creative-navigation-menus/">30 Creative Navigation Menus</a><br>
It’s not always easy creating a navigation menu that stands out, and also serves its purpose without getting in the way. Sites that have a huge number of category pages in particular can be quite daun...</p>
<p><a href="http://www.smashingmagazine.com/2011/06/27/useful-ideas-and-guidelines-for-good-web-form-design/#comments">Useful Ideas And Guidelines For Good Web Form Design</a><br>
The input form is an essential element of almost any website or application these days. Input is a core method of interaction, and in many cases it represents the hard conversion point between success...</p>
<p><a href="http://feedproxy.google.com/~r/SmashingApps/~3/cZheUyJwIM4/50-minimalist-and-stylish-free-wordpress-themes.html">50 Minimalist And Stylish Free WordPress Themes</a><br>
WordPress is the preferred content management system of many bloggers and internet marketers owing to many reasons. Out of them its easily available theme is the most important reason that can complet...</p>
<p><a href="http://feedproxy.google.com/~r/creativeoverflowblog/~3/fIShLlAqJCU/">Should Freelance Designers Run Design Blogs?</a><br>
To blog or not to blog -that is the question. For freelancers, especially designers, it can be a particularly difficult question. Blogs have popped up as one of the most recommended methods for a free...</p>
<p><a href="http://www.1stwebdesigner.com/css/object-oriented-css/">An Introduction to Object Oriented CSS</a><br>
With richer interactions and media heavy pages mushrooming on the web, creating web pages, which load faster and respond well has become a challenge. Separating the content, presentation and behavior ...</p>
<p><a href="http://speckyboy.com/2011/06/26/html5-and-css3-form-references-resources-and-tutorials/">HTML5 and CSS3 Form References, Resources and Tutorials</a><br>
Advertise here with BSA This article explores some of the new HTML5 form features and how it has greatly improved text inputs, search boxes and other form fields by providing better and cleaner contro...</p>
<p><a href="http://feedproxy.google.com/~r/Line25/~3/SRQeshFDYkw/showcase-of-impressive-design-process-explanations">Showcase of Impressive Design Process Explanations</a><br>
A common feature amongst the top design portfolio and agency websites is a visually presented explanation of their design process. This simple idea of describing how a potential client’s project will ...</p>
<p><a href="http://webdesignledger.com/inspiration/25-examples-of-capital-letters-usage-in-web-design">25 Examples of Capital Letters Usage in Web Design</a><br>
Advertise here with BSA Letter case -in orthography and typography is the distinction between the larger majuscule (capital, caps, upper-case, upper case, or uppercase) and smaller minuscule (lower-ca...</p>
<p><a href="http://feedproxy.google.com/~r/smileycat/~3/dNZD0pO_2ps/002564.php">8 Reasons Why Bad Web Design Decisions Get Made</a><br>
Sometimes when I'm struggling to complete a task on a website (or am watching my wife throw her arms up in frustration), I ask myself 'What genius decided to build it like that?' Having been on the ot...</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Last Weeks Hot Topics (26/06/11)</title>
      <link href="https://www.alwaystwisted.com/articles/last-weeks-hot-topics-260611.html"/>
      <updated>2011-06-26T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/last-weeks-hot-topics-260611.html</id>
      <content type="html">
        <![CDATA[
        <p>Here's a quick selection from this weeks blog posts I've found interesting from my RSS feed.</p>
<p>I hope you do too.</p>
<p>So, sit back, Relax!. Have a cup of Joe.</p>
<p>Enjoy.</p>
<p>If you've got any suggestions or you've got a blog I should add to my list of many then catch me on <a href="http://www.twitter.com/sturobson">twitter</a></p>
<h2 id="tutorials%2C-tricks-%26-plugins" tabindex="-1">Tutorials, Tricks &amp; Plugins</h2>
<p><a href="http://www.css-tricks.com/9876-learn-canvas-snake-game/">Learning Canvas: Making A Snake Game</a> from CSS-Tricks</p>
<p><a href="http://www.webresourcesdepot.com/lightweight-jquery-plugin-for-overlays-simple-overlay/">A jQuery plugin for Overlays</a> from Web Resources Depot</p>
<p><a href="http://www.onextrapixel.com/2011/06/20/creating-depth-in-web-design-5-design-tricks/?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+onextrapixel+%28Onextrapixel%29">Creating Depth in Web Design: 5 Design Tricks</a> from One Extra Pixel</p>
<p><a href="http://www.tripwiremagazine.com/2011/06/showcase-and-tips-how-to-create-effective-landing-page-designs.html?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+tripwiremagazine+%28tripwire+magazine%29">How To Create Effective Landing Page Design</a> from Tripwire Magazine</p>
<h2 id="round-ups%2C-best-ofs-%26-compilations" tabindex="-1">Round-Ups, Best-Ofs &amp; Compilations</h2>
<p><a href="http://www.smashingapps.com/2011/06/23/50-creatively-designed-unusual-and-entertaining-404-error-pages-worth-checking-out.html?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+SmashingApps+%28Smashing+Apps%29">50 Creatively Designed 404 Error Pages</a> from Smashing Apps</p>
<p><a href="http://www.youthedesigner.com/2011/06/23/51-high-quality-free-texture-packs-to-download/">51 Hi Quality Textures Packs</a> from You The Designer</p>
<p><a href="http://vandelaydesign.com/blog/design/free-photoshop-patterns/">UltimateRound Up of Free Photoshop Patterns</a> from Vandelay Design</p>
<p><a href="http://psd.fanextra.com/articles/the-best-free-sans-serif-fonts-for-designers/">The Best Free Sans-Serif Fonts</a> from PSDFAN EXTRA</p>
<h2 id="inspiration%2C-thought-provoking-%26-opinion-pieces" tabindex="-1">Inspiration, Thought Provoking &amp; Opinion Pieces</h2>
<p><a href="http://www.smashingmagazine.com/2011/06/22/following-a-web-design-process/#comments">Following A Web Design Process</a> from Smashing Magazine</p>
<p><a href="http://www.webdesignerdepot.com/2011/06/how-to-avoid-a-redesign-failure/">How To Avoid A Redesign Failure</a> from Webdesigner Depot</p>
<p><a href="http://graphicdesignblender.com/design-portfolio-attracting-clients">Ensure Your Design Portfolio Is Attracting Client</a> from Graphic Design Blender</p>
<p><a href="http://www.cennydd.co.uk/2011/why-personas-should-use-real-photos/?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+cennydd+%28Ineffable++%2F++Cennydd+Bowles%29">Why Personas Should Use Real Photos</a> from Cennydd Bowles</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>A Spaces Cowboy</title>
      <link href="https://www.alwaystwisted.com/articles/a-spaces-cowboy.html"/>
      <updated>2011-06-24T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/a-spaces-cowboy.html</id>
      <content type="html">
        <![CDATA[
        <p>As I've mentioned, I've got rid of my 27' iMac and have shrunk my 'screen real estate' down to a 13' MacBook Pro. I've had it a little over a week now. I've upgraded bits of it already (I'm gonna post about that) But it wasn't until <a href="http://www.twitter.com/sazzy">@sazzy</a> tweeted this morning that she's just <a href="http://twitter.com/sazzy/status/84227428129583104">'discovered Spaces on OS X'</a>.</p>
<p>Until that tweet, for some reason, I'd completely forgotten about <a href="http://www.apple.com/macbookpro/software.html#gallery-macosx-spaces">Spaces</a>. I've spent that last week having my twitter client, browser, photoshop, coda and anything else I open in the same 'window space'.</p>
<p>It's awesome.</p>
<p>I now have my email and twitter client in one space, coda in another, photoshop another, everything else in 'space number one'.</p>
<p>You should, if you haven't already, really check it out. With keyboard shortcuts it makes switching so frickin' easy.</p>
<p>Me LOVES IT!</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Last Weeks Hot Topics (19/06/11)</title>
      <link href="https://www.alwaystwisted.com/articles/last-weeks-hot-topics-190611.html"/>
      <updated>2011-06-19T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/last-weeks-hot-topics-190611.html</id>
      <content type="html">
        <![CDATA[
        <p>Hey,</p>
<p>I read a lot of blogs, my RSS list is humongous . I've been meaning to start a post like this for ages. For the moment (well hopefully just this week) it's going to just be a list. In the future (well hopefully next week) it will become a bit more 'finished'.</p>
<p>How do I do it? Quite easily. I've solely use NewsRack on my iPhone for reading my RSS. When I find something I thinks of interest when reading through the posts I mark it as new again. Then I'll send that list in an email to myself which in turn gets put into this post.</p>
<p>So, sit back, Relax!, Have a cup of Joe.</p>
<p>Enjoy.</p>
<p>(If you've got any suggestions or perhaps you've got a blog post I should add to my list then catch me on twitter - <a href="http://twitter.com/sturobson">@sturobson</a></p>
<p><a href="http://www.webresourcesdepot.com/free-wordpress-e-commerce-plugin-jigoshop/">Free WordPress E-Commerce Plugin – Jigoshop</a></p>
<p><a href="http://feedproxy.google.com/~r/ProbloggerHelpingBloggersEarnMoney/~3/ZA46iT0rX88/">Optimize the Most Underutilized Page of Your Blog</a></p>
<p><a href="http://csswizardry.com/2011/06/what-is-inuit-css/">What is inuit.css?</a></p>
<p><a href="http://feedproxy.google.com/~r/productivedreams/~3/y5e6EtxND3Y/">12 Steps to better navigation</a></p>
<p><a href="http://feedproxy.google.com/~r/savedelete/~3/KnG5-ukOG88/creating-a-impressive-headlinetagline-and-10-great-examples.html">Creating a Impressive Headline / Tagline &amp; 10 Great Examples</a></p>
<p><a href="http://css-tricks.com/2011/06/screen-resolution-notequalto-browser-window-9778">Screen Resolution ≠ Browser Window</a></p>
<p><a href="http://feedproxy.google.com/~r/SmashingApps/~3/X51n-bZyeXo/50-useful-and-free-html-newsletter-templates.html">50 Useful And Free HTML Newsletter Templates</a></p>
<p><a href="http://acrisdesign.com/2011/06/ultimate-collection-of-free-photoshop-pattern/">Ultimate Collection Of Free Photoshop Pattern</a></p>
<p><a href="http://www.robbiemanson.com/articles/a-new-approach-part-i/">A New Approach (Part I)</a></p>
<p><a href="http://feedproxy.google.com/~r/FreelanceSwitch/~3/FGPsxQo_4sk/">Ask FreelanceSwitch: Portfolios and Blog Content</a></p>
<p><a href="http://www.1stwebdesigner.com/design/stay-organized-and-stay-ahead-of-your-competition/">Stay Organized and Stay Ahead of Your Competition</a></p>
<p><a href="http://feedproxy.google.com/~r/artatm/~3/xjIBuT6kKvI/">50 Beautifully Designed Single Page Websites</a></p>
<p><a href="http://feedproxy.google.com/~r/speckboy-design-magazine/~3/U3PpynKA_Fw/">Home Office Tips – Eliminating Distractions When Working From Home</a></p>
<p><a href="http://feedproxy.google.com/~r/tripwiremagazine/~3/4rKVXjZ1Vyo/what-theme-options-does-your-wordpress-theme-need.html">What theme options does your WordPress theme need?</a></p>
<p><a href="http://www.webdesignerdepot.com/2011/06/why-typography-rules/">Why typography is the Web’s greatest media format</a></p>
<p><a href="http://www.1stwebdesigner.com/design/web-typography-guide/">A Simple Guide to Improving Web Typography</a></p>
<p><a href="http://feedproxy.google.com/~r/VigetInspire/~3/M_UbBkTfIZ4/">In Defense of the Humble, Often Overlooked Contact Page</a></p>
<p><a href="http://www.crazyleafdesign.com/blog/free-social-icons/">Picons Social Pack, Free High Quality Social Icons</a></p>
<p><a href="http://spyrestudios.com/750-free-photoshop-brushes-to-download/">750+ Free Photoshop Brushes to Download</a></p>
<p><a href="http://feedproxy.google.com/~r/vectortuts/~3/1IbUjx_bR_A/">How to Make a Happy and Safe Office Space</a></p>
<p><a href="http://webdesignledger.com/tips/strategies-for-task-management-working-with-clients">Strategies for Task Management Working with Clients</a></p>
<p><a href="http://www.1stwebdesigner.com/design/how-to-improve-web-designer/">9 Tips on How To Improve Yourself as a Web Designer</a></p>
<p><a href="http://feedproxy.google.com/~r/WebDesignerNotebook/~3/lyIw9KBZfXQ/">The Wonderful calc() Function</a></p>
<p><a href="http://acrisdesign.com/2011/06/responsive-web-design-examples-and-tutorials/">Responsive Web Design: Examples And Tutorials</a></p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Time for a change...</title>
      <link href="https://www.alwaystwisted.com/articles/time-for-a-change.html"/>
      <updated>2011-06-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/time-for-a-change.html</id>
      <content type="html">
        <![CDATA[
        <p>I've sold my iMac. Finally. I knew I should have attempted to sell it before the new range of iMacs were released. But no, I waited. I'm really happy it's gone though. It's gone to a great company down in Brighton. A company that I would love to work for in fact. So at least part of me is now by the seaside.</p>
<p>So what have I done with my spoils? I managed to get a healthy £1000 for my iMac which included a magic trackpad and remote control. So with that I have purchased, and am using now, a 2011 13' MacBook Pro. It's the low end model available for £999 from Apple. Mine's a refurbished model so I got it for £849 instead. So far I've not notice any difference in what I'd expect from a 'brand new' MacBook. Except for the boring plain white packaging.</p>
<p>It's quite a jump. It really is. For 18 months or so I've had the luxury of 27' of Apple LED display in the iMac and now I've got a 'tiny' 13 inches. But it's fine. That's where the multi finger gestures on the track pad come in really handy. That's the other thing I'm trying to get used to after using a fat old magic mouse for a year and half I've got to get used the the fact it's my fingers and not my hand that has got to move the cursor around the screen now. But, I'm getting used to it.</p>
<p>So what now? Well. Now that I can literally sit anywhere and work I'm hoping this will up my productivity in the evenings when I mainly freelance. Just by reading this you can see I'm 'blogging' again.</p>
<p>What's in the pipeline? I've got several client projects 'on the go' so I'm hoping to finish these ASAP and then get my 'freelancer for hire' site un and running.</p>
<p>So plenty to do AND I hope to blog more. Fingers crossed.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Ideas Of March</title>
      <link href="https://www.alwaystwisted.com/articles/ideas-of-march.html"/>
      <updated>2011-03-15T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/ideas-of-march.html</id>
      <content type="html">
        <![CDATA[
        <p>Whilst at 'the day job' this morning I checked twitter to see that <a href="http://www.twitter.com/MrQwest">@MrQwest</a> had tweeted a blog post entitled <a href="http://mrqwest.co.uk/blog/148/ideas-of-march-ideasofmarch">'Ideas if March'</a>. Having seen his previous tweets about having a load of blog ideas I though this would be a brief list of said ideas. I was wrong. In fact Anthony's blog post took me to <a href="http://shiflett.org/blog/2011/mar/ideas-of-march">a post</a> written by <a href="http://www.twitter.com/Shiflett">Chris Shiflett</a>.</p>
<p>I love twitter as a platform for chatting, asking and answering questions but sometimes what is being said has to be truncated to fit into the 140 charecters. As such conversations can become disjointed and you may find yourself including someone who left the chat a while back.</p>
<p>I've only recently started blogging. I've been 'designing websites' since the early days. I can remember the joy when I could use a:hover. I even found an old site the other day that was 'best viewed' in IE 4+ and NN 4+ but, I've only just started blogging.</p>
<p>Part of the reason is because I like the idea of sharing what techniques I find/create using the new CSS3 properties but I've found that it's a good outlet for a <a href="http://alwaystwisted.com/post.php?s=2011-02-20-dont-let-your-menu-take-over">bit of a rant</a> that I can't quite fit into 140 charecters.</p>
<p>Before I digress anymore let's get on with it. In Chris's post he outlined several things he'd like us to do in our Ideas of March post.</p>
<ul>
<li>Write a post called Ideas of March</li>
<li>List some of the reasons you like blogs.</li>
<li>Pledge to blog more the rest of the month.</li>
<li>Share your thoughts on Twitter with the <a href="http://search.twitter.com/search?q=%23ideasofmarch">#ideasofmarch</a> hashtag.</li>
</ul>
<h3 id="why-i-like-blogs" tabindex="-1">Why I Like Blogs</h3>
<ul>
<li>There's room to breath outside of 140 charecters.</li>
<li>You can keep the context of your topic of discussion.</li>
<li>You can evolve your initial ideas and talk more in depth about the chosen subject.</li>
<li>Each posts helps the next.</li>
</ul>
<h3 id="why-i-don't-like-blogs" tabindex="-1">Why I Don't Like Blogs</h3>
<p>There is always a but.</p>
<ul>
<li>Comments, I'd much rather you say what you think in your own post. Rather than rush it in a blog comment or even a tweet.</li>
</ul>
<h3 id="in-the-end" tabindex="-1">In The End</h3>
<p>I've never really fallen out with blogs, my RSS feed shows me that. But I feel that we do need a revival. If you blog about what you're thinking it's better documented than in a barrage of tweets. If you don't agree with something, write it down in long form. If you do agree with something, write it down in long form. If you have an idea, write it down in long form. To help us all make sense of this infant technology write it down in long form so that we can all shape it to be the best is can be.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Geek Ninja Battle Night - a review of sorts</title>
      <link href="https://www.alwaystwisted.com/articles/geek-ninja-battle-night-a-review-of-sorts.html"/>
      <updated>2011-03-12T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/geek-ninja-battle-night-a-review-of-sorts.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/geek-ninja-battle-night-image.jpeg" alt="geek ninja battle night image" loading="lazy" decoding="async"></p>
<p>Yesterday I ventured from the cosiness of my West Country Mansion to drive the motorways and A roads of Blighty to the seaside town of Brighton. Attending <a href="http://geekninjafactory.com/geek-ninja-battle-night-mobile-web-vs-native">The Geek Ninja Battle Night</a> that was being run by <a href="http://www.twitter.com/aral">Aral Balkan</a> which included himself as one of the 4 speakers with <a href="http://www.twitter.com/sazzy">Sarah Parmenter</a>, <a href="http://www.alwaystwisted.com/blog/www.twitter.com/rem">Remy Sharp</a> and <a href="http://www.alwaystwisted.com/www.twitter.com/Malarkey">Andy Clarke</a>.</p>
<p>It was a novel (an amazingly brilliant) idea to give an evening event a discussion topic and having the two 'sides' set to 'battle' over which 'side' is best at the task in hand. For this event (hopefully the first of many) the subject matter was designing and developping for mobile. There were two teams, Team Web (blue) who were represented by Andy and Remy pitted against Team Native (red) who were aptly represented by Sarah and Aral.</p>
<p>I did take <a href="http://instagr.am/p/CLN__/">some notes</a> but they were few and far between as I spent most of the time just soaking up the presentations like a sponge.</p>
<p>Because of this I can only discuss what I took away from the evening. Anything more and I wouldn't be sure if I dreamt bits of it or not. This 'idea' came to me as Aral was gesticulating at the front of the room with so much passion and energy.</p>
<p>Here goes...</p>
<p>We shouldn't be worrying about how we design for the devices that access the internet and what is the best technology to use first. We should be thinking first and foremost about the content and the context in which that content will be used, irregardless of it being within a native app or a 'web app' (sorry Andy).</p>
<p>What matters is when I'm 'in town' and I fancy a pizza for a spot of lunch I can get out my smartphone, open the browser, go to the pizza express web site which takes me to what I need to know. I want to know where the nearest chain is, I'm not bothered by company literature, big images. I want to find the nearest chain, get a telephone number and make a reservation.</p>
<p>Of course, this could all be done using the specific os's native coding. But what I'm getting at, and I'm probably labouring (not laboring) the point, is that it's the content I required for the context I was in.</p>
<p>You're on a mobile phone. You don't neccesarily want to read a ton of stuff. You are going to be very task orientated.</p>
<p>The only thing I would emplore you to do in which ever way you develop for mobile when choosing native or web is <strong>always</strong> include a link to the full site.</p>
<p>I only managed a quick thank you to Aral at the end and didn't get to say hi to Sarah, Andy (we've chatted about books &amp; amazon on the phone) or Rem. But thank you all. It was a great evening, I hope, had by all.</p>
<p>nb. the image above has been taken from Aral's Geek Ninja Battle Night, I'm awaiting an ok in using it. So it may change :)</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Creating A CSS3 Paper Stack</title>
      <link href="https://www.alwaystwisted.com/articles/creating-a-css3-paper-stack.html"/>
      <updated>2011-03-06T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/creating-a-css3-paper-stack.html</id>
      <content type="html">
        <![CDATA[
        <p>On January 12th 2011 I found myself like most days, browsing through the various new shots on<a href="http://www.dribbble.com/">Dribbble</a> when I came across a <a href="http://dribbble.com/shots/98799-Target-locked">nice little shot</a> by Dan Rubin.</p>
<p>I liked the little paper stack effect that <a href="http://www.twitter.com/DanRubin">Dan</a> had created for this call to action. I liked it so much I wondered if it could be created in CSS rather than having a background image with the stack. Having previously experimented with the :before and :after CSS propertie on my <a href="../post.php%EF%B9%96s=2011-01-29-css3-3d-ribbons-using-2d-transforms.html">CSS3 3D Ribbons</a> post using 2D Transforms and box-shadow.</p>
<p>So I went about the interwebs and found a rough and ready 'paper' texture and set about creating this quick example <a href="http://alwaystwisted.com/backstage/notes.html">CSS3 Paper Stack</a></p>
<p>I found a nice little 'handwritten' font from <a href="http://www.fontsquirrel.com/">font squirrel</a> to make the demo a little more realistic and aligned the text as best possible to run along the lines of the background paper. To get the most out of this demo page it'd be best to view the code source.</p>
<p>Below is a highlight of the code to keep it as simple as possible for this blog post.</p>
<p>Also note I have only tested the <a href="http://alwaystwisted.com/backstage/notes.html">demo CSS3 paper stack</a> in latest versions of Chrome, Safari, Firefox and Opera on my iMac running Snow Leopard. I have not tried this in any other browser and have noticed that Opera isn't playing ball with the -o-transform property. I could probably guess the :before and :after properties won't work correctly in IE.</p>
<p>This is just another proof of concept to show what possibilites there are with the new CSS3 properties</p>
<p>HTML</p>
<p>&lt;!doctype html&gt;</p>
<p><head></p>
<p><meta charset='UTF-8'></p>
<p></head></p>
<p>e
   <body></p>
<div id='notes'></div><p></body></p>
<p></html></p>
<p>CSS</p>
<p>#notes {</p>
<p>position: relative;</p>
<p>width: 320px;</p>
<p>height: 420px;</p>
<p>border:1px solid #000000;</p>
<p>-webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>-moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>#notes:before {</p>
<p>z-index: -1;</p>
<p>position: absolute;</p>
<p>top:3px;</p>
<p>left:0;</p>
<p>width: 320px;</p>
<p>height: 420px;</p>
<p>content: '';</p>
<p>background-color: #444;</p>
<p>border:1px solid #000000;</p>
<p>-webkit-transform: rotate(3deg);</p>
<p>-moz-transform: rotate(3deg);</p>
<p>-o-transform: rotate(3deg);</p>
<p>transform: rotate(3deg);</p>
<p>-webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>-moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>}</p>
<p>#notes:after {</p>
<p>z-index: -2;</p>
<p>position: absolute;</p>
<p>top:3px;</p>
<p>left:0;</p>
<p>width: 320px;</p>
<p>height: 420px;</p>
<p>content: '';</p>
<p>background-color: #444;</p>
<p>border:1px solid #000000;</p>
<p>-webkit-transform: rotate(-2deg);</p>
<p>-moz-transform: rotate(-2deg);</p>
<p>-o-transform: rotate(-2deg);</p>
<p>transform: rotate(-2deg);</p>
<p>-webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>-moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.8);</p>
<p>}</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Don&#39;t Let Your Menu Take Over</title>
      <link href="https://www.alwaystwisted.com/articles/dont-let-your-menu-take-over.html"/>
      <updated>2011-02-20T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/dont-let-your-menu-take-over.html</id>
      <content type="html">
        <![CDATA[
        <p><img src="/images/articles/mqnav.jpg" alt="a montage of several websites on what would be a small screen showing their navigation" loading="lazy" decoding="async"></p>
<p>The <a href="http://www.w3.org/TR/css3-mediaqueries/">CSS3 Media Queries Module</a> is fast becoming the love of the 'modern web designer'. It's great, I love it. It's fantastic what you can do these days whilst creating a website compared to the nested tables I was dealing with when I first started out.</p>
<p>But there's a problem, only a slight problem but one that is increasingly annoying me (hence this little rant).</p>
<p>The iPhone is an excellant device, it's advanced web design for mobile devices at a phenomanal pace (I can remember attempting to build a WAP site, once). With the iPhone (there are other devices available) you get 320px by 480px of 'screen real estate' to play with.</p>
<h2 id="my-gripe%2Fmoan%2Frant%3F" tabindex="-1">My gripe/moan/rant?</h2>
<h2 id="a-lot-of-you-are-filling-this-space-with-your-navigation!" tabindex="-1">A lot of you are filling this space with your navigation!</h2>
<p>I use my iPhone everyday, almost too much. As my real world job is nothing to do with web design and is two miles up a farm track near the <a href="http://www.phrases.org.uk/meanings/52650.html">back of beyond</a> I access the internet, twitter, ebay and my RSS via my iPhone as that's the only access I have for at least 9 hours of the day.</p>
<p>When I visit a website, I don't mind if it doesn't use CSS3 Media Queries, hey it's only just started to get implemented. I've got my fingers so I can pinch and zoom to my hearts content, but if your site uses CSS3 Media Queries please don't show me a whole screen of your navigation to start with.</p>
<p>I know that screen size is small, I know that you think it looks good but honestly it doesn't have to be that big, you're not designing a Fisher Price 'My First Website'. The Apple <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html%23//apple_ref/doc/uid/TP40006556-CH20-SW1">Human Interface Guidelines</a> suggest an optimum size of 44px by 44px for a tappable area. That's not 44px high by 320px wide that's a 44px by 44px square. I know you're probaly saying to yourself that you can't fit the links in that space, I agree, but you can fit more than one link in a line on a screen size that has a width of 320px or more.</p>
<p>So please, be a bit careful when using Media Queries so that your site adapts to the browser window. I don't need a screen of navigation, I don't know what's on the rest of your homepage yet.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Create a CSS3 Media Queries Easter Egg</title>
      <link href="https://www.alwaystwisted.com/articles/create-a-css3-media-queries-easter-egg.html"/>
      <updated>2011-02-18T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/create-a-css3-media-queries-easter-egg.html</id>
      <content type="html">
        <![CDATA[
        <p>A day does not pass without me seeing something about CSS3 Media Queries on the Internet. Be it a new article highlighting the pros or slating the cons, a tutorial showing you how to use them to create an 'iphone version' of your website or people tweeting about the module.</p>
<p>One thing has struck me about all this recently and that is; apart from us as web designers having a poke around a fellow designer newly finished site or clients site would anyone else re-size the browsers (if possible) and notice the changes that are put in place using this part of the CSS3 spec.</p>
<p>Whilst I was designing this blog (it's a perpetual work in progress) I thought it'd be kind of cool to add a slight colour change of the main background when the browser window is re-sized or for when your on an smart phone/iPhone or a iPad/Tablet/Netbook.</p>
<p>Whilst I was using the CSS3 media queries to set my widths for the appropriate 'mobile' devices I thought I'd use the new CSS3 transitions so that people on a big screen for if and when the re-size the browser would have a nice fade between colours.</p>
<p>I set about creating a quick <a href="../playground/media-queries-easter-egg-demo.html">test demo page</a> to see what would happen, the css for this page is shown below.</p>
<p>Don't forget to resize your browser or flip your iPhone/iPad.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">body</span> <span class="token punctuation">{</span>
	<span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
	<span class="token property">width</span><span class="token punctuation">:</span>100%<span class="token punctuation">;</span>
	<span class="token property">background-color</span><span class="token punctuation">:</span> #ccc<span class="token punctuation">;</span>
	<span class="token property">-webkit-transition</span><span class="token punctuation">:</span> all 2s ease<span class="token punctuation">;</span> <span class="token comment">/* Saf3.2+, Chrome */</span>
	<span class="token property">-moz-transition</span><span class="token punctuation">:</span> all 2s ease<span class="token punctuation">;</span> <span class="token comment">/* FF3.7+ */</span>
	<span class="token property">-o-transition</span><span class="token punctuation">:</span> all 2s ease<span class="token punctuation">;</span> <span class="token comment">/* Opera 10.5 */</span>
	<span class="token property">transition</span><span class="token punctuation">:</span> all 2s ease<span class="token punctuation">;</span>

	<span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span>320px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
		<span class="token selector">body</span> <span class="token punctuation">{</span> 
			<span class="token property">background-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>

	<span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span>480px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
		<span class="token selector">body</span> <span class="token punctuation">{</span>
			<span class="token property">background-color</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>

	<span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span>768px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
		<span class="token selector">body</span> <span class="token punctuation">{</span>
			<span class="token property">background-color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>

	<span class="token atrule"><span class="token rule">@media</span> screen <span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token property">min-width</span><span class="token punctuation">:</span>1024px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
		<span class="token selector">body</span> <span class="token punctuation">{</span>
			<span class="token property">background-color</span><span class="token punctuation">:</span> green<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span></code></pre>
<p>As you can see from the demo it was a quick 'test case' to see the idea in a really obvious way. On this site, hopefully, it is a little more subtle.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Fuse 2 Fonts and get to SXSWi</title>
      <link href="https://www.alwaystwisted.com/articles/fuse-2-fonts-and-get-to-sxswi.html"/>
      <updated>2011-02-17T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/fuse-2-fonts-and-get-to-sxswi.html</id>
      <content type="html">
        <![CDATA[
        <p>So, I didn't win the <a href="http://netmag.co.uk/">.net magazine</a> competition for a pair of tickets to SXSWi this year.</p>
<p>Thanks to <a href="http://www.twitter.com/candiRSX">Candi</a> I've just entered a competition at <a href="http://fontfuse.webink.com/">Font Fuse</a> for the chance to get some kick-ass VIP tickets to SXSWi. I probably won't win, I never win. Well, I haven't won anything since 1988 when I got a bunch of Panini stickers and the 1988 American Football sticker album, but I digress.</p>
<p><img src="/images/articles/simpleelegance.png" alt="simple elegance image" loading="lazy" decoding="async"></p>
<p>Sure picking two fonts can be like taking candy from a baby or it can be the most difficult thing you have to suss out. I generally stick to one font pair in almost all the work I do when I start and I'm not entirely sure if the fonts I've chosen for this piece of the internet I call mine are entirely 'right'.</p>
<p>I was thinking that really what both fonts need to do is</p>
<ol>
<li>complement each other</li>
<li>be 'easy' on the eye</li>
<li>not be imposing on the page</li>
<li>be simple</li>
<li>be elegant</li>
</ol>
<p>Having a quick look at the vast amount of fonts available i picked my two favourites for the task. I chose some nice blues for the background and the heading and body text.</p>
<p>I wasn't too satisfied with the standard text placed in the body so I found a nice little quote from Robert Louis Stevenson</p>
<blockquote>
<p>The web, then, or the pattern, a web at once sensuous and logical, an elegant and pregnant texture: that is style, that is the foundation of the art of literature.</p>
</blockquote>
<p>So if you have a spare 5 minutes why not take a look at the competion, have a go yourself, look at other font pairings for some great typographic inspiration or just <a href="http://fontfuse.webink.com/pairing/stu/simple-elegance">vote for my pairing</a>.</p>

      ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>CSS3 3D Ribbons using 2D Transforms</title>
      <link href="https://www.alwaystwisted.com/articles/css3-3d-ribbons-using-2d-transforms.html"/>
      <updated>2011-01-29T00:00:00Z</updated>
      <id>https://www.alwaystwisted.com/articles/css3-3d-ribbons-using-2d-transforms.html</id>
      <content type="html">
        <![CDATA[
        <p>&lt;&gt; It's a 'trend' of the moment which seems to be fading slightly but you probably won't be able to go a day, let alone an hour, without seeing some form of 'ribbon' being employed in the design of a website.</p>
<p>These are usually created with graphics software such as Photoshop or Fireworks but with the modern browsers of today and the great tools that we can use within the CSS3 spec we are able to create this effect using just the code.</p>
<p>I got inspired to try this out by two things. First was a post from <a href="http://www.pvmgarage.com/2010/01/how-to-create-depth-and-nice-3d-ribbons-only-using-css3/">PVM Garage</a> showing you how to add a nice 3D ribbon to your page using CSS3. I thought this was really good but I wasn't happy with the <a href="http://en.wikipedia.org/wiki/Tag_soup">'tag soup'</a> that was being used to get the effect working. I then, through <a href="http://www.twitter.com/Sturobson">Twitter</a> saw that <a href="http://www.twitter.com/Matthamm">Matt Hamm</a> had created some cool <a href="http://www.matthamm.com/notebook/?p=7">CSS3 box-shadow page curls</a> and seeing that he was using the :before and :after elements attempted to recreate the 3D ribbon with just one DIV.</p>
<p>I posted a whole page in my <a href="http://www.alwaystwisted.com/blog/backstage.php">back stage area</a> where I will be putting all of my 'experiments' in the future (note, this whole site is a in current state of 'work in progress').</p>
<p>Then the latest copy of <a href="http://www.netmag.co.uk/">.net (issue 212)</a> and there was a tutorial for 3D ribbons using CSS like the PVM Garage example I thought I'd better create a 'proper post' on what I did just after Christmas 2010.</p>
<p><img src="/images/articles/css3-3d-ribbon.png" alt="3D ribbons example" loading="lazy" decoding="async"></p>
<p>The code below would create something along the lines of what is shown in the image above. As you can see on the <a href="../backstage/css3-ribbon.html">backstage page</a> there are some more examples of what is possible using CSS3 2D transforms, box-shadow, rounded corners and CSS :before and :after elements.</p>
<h3 id="html" tabindex="-1">HTML</h3>
<p>&lt;!doctype html&gt;</p>
<p><head></p>
<p><meta charset='UTF-8'></p>
<p></head></p>
<p><body></p>
<p><div id ='container'></p>
<div id='ribbon'></div><p></div></p>
<p></body></p>
<p></html></p>
<h3 id="css" tabindex="-1">CSS</h3>
<p>#ribbon {</p>
<p>position: relative;</p>
<p>top:40px;</p>
<p>left:-20px;</p>
<p>width: 960px;</p>
<p>height:100px;</p>
<p>background-color: #999;</p>
<p>float: left;</p>
<p>-webkit-box-shadow: 0px 0px 2px #000;</p>
<p>-moz-box-shadow: 0px 0px 2px #000;</p>
<p>box-shadow: 0px 0px 2px #000;</p>
<p>border-bottom: 1px solid #000;</p>
<p>}</p>
<p>#ribbon:before {</p>
<p>z-index: -1;</p>
<p>position: absolute;</p>
<p>top:10px;</p>
<p>left:0;</p>
<p>width: 20px;</p>
<p>height: 101px;</p>
<p>content: '';</p>
<p>background-color: #444;</p>
<p>-webkit-transform: skewY(45deg);</p>
<p>-moz-transform: skewY(45deg);</p>
<p>-o-transform: skewY(45deg);</p>
<p>transform: skewY(45deg);</p>
<p>-webkit-box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>-moz-box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>}</p>
<p>#ribbon:after {</p>
<p>z-index: -2;</p>
<p>position: absolute;</p>
<p>top:10px;</p>
<p>right:0;</p>
<p>width: 20px;</p>
<p>height: 101px;</p>
<p>content: '';</p>
<p>background-color: #444;</p>
<p>-webkit-transform: skewY(-45deg);</p>
<p>-moz-transform: skewY(-45deg);</p>
<p>-o-transform: skewY(-45deg);</p>
<p>transform: skewY(-45deg);</p>
<p>-webkit-box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>-moz-box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>box-shadow: inset 1px -1px 3px #000, 1px 1px 3px #000;</p>
<p>}</p>

      ]]>
      </content>
    </entry>
  
</feed>