Design Token Refactoring
Design Token Refactoring
Design token refactoring restructures existing token systems to improve architecture, naming, organization, or maintainability without changing the visual output. As token systems mature and requirements evolve, refactoring keeps the system healthy. Thoughtful refactoring improves developer experience while managing the disruption inherent in changing established patterns.
What Is Design Token Refactoring
Design token refactoring is the process of improving token system structure while preserving functionality. This includes renaming tokens, reorganizing hierarchies, consolidating duplicates, and aligning with better architectural patterns. Unlike breaking changes that alter visual output, refactoring maintains equivalent behavior.
Refactoring addresses accumulated technical debt in token systems without requiring consuming applications to update their visual designs.
How Design Token Refactoring Works
Refactoring scenarios:
Naming convention updates:
/* Before: Inconsistent naming */
{
"colorPrimary": "#3B82F6",
"color-secondary": "#6B7280",
"COLOR_ACCENT": "#F59E0B"
}
/* After: Consistent convention */
{
"color.primary": "#3B82F6",
"color.secondary": "#6B7280",
"color.accent": "#F59E0B"
}
Hierarchy restructuring:
/* Before: Flat structure */
{
"primary-text-color": "#171717",
"secondary-text-color": "#525252",
"primary-background": "#ffffff"
}
/* After: Hierarchical */
{
"color": {
"text": {
"primary": "#171717",
"secondary": "#525252"
},
"background": {
"primary": "#ffffff"
}
}
}
Duplicate consolidation:
/* Before: Same value, different tokens */
{
"header-white": "#ffffff",
"card-white": "#ffffff",
"modal-white": "#ffffff"
}
/* After: Single semantic token */
{
"color.surface.primary": "#ffffff"
}
Key Considerations
- Refactoring should be isolated from value changes
- Codemods automate consumer updates
- Deprecation periods ease transition
- Communication prepares consumers
- Testing verifies equivalence
- Incremental refactoring reduces risk
- Documentation updates alongside refactoring
- Rollback capability provides safety
Common Questions
How should refactoring be planned?
Refactoring planning balances improvement goals with disruption costs.
Assessment phase:
Current state analysis:
- Token inventory: 342 tokens
- Naming inconsistencies: 45 tokens
- Duplicates: 23 value groups
- Missing semantic layer: 78 primitives used directly
Impact assessment:
- Consuming applications: 12
- Estimated references: 2,400
- Team coordination needed: 8 teams
Goal definition:
Refactoring goals:
1. Consistent naming convention (kebab-case with dots)
2. Complete semantic layer
3. No duplicate values
4. Clear tier separation
Success criteria:
- All tokens follow naming convention
- All component usage through semantic tokens
- Duplicate values consolidated
Phased approach:
Phase 1 (Sprint 1-2): Naming consistency
- Add deprecation aliases
- Communicate changes
- Run codemods
Phase 2 (Sprint 3-4): Semantic layer
- Create semantic tokens
- Update references
- Deprecate direct primitive usage
Phase 3 (Sprint 5): Cleanup
- Remove deprecated tokens
- Update documentation
- Training refresh
How should codemods support refactoring?
Codemods automate consumer code updates, reducing manual effort and errors.
Rename codemod:
// jscodeshift transform
module.exports = function(file, api) {
const j = api.jscodeshift;
const renames = {
'colorPrimary': 'color.primary',
'color-secondary': 'color.secondary'
};
return j(file.source)
.find(j.StringLiteral)
.filter(path => renames[path.value])
.forEach(path => {
path.replace(j.stringLiteral(renames[path.value]));
})
.toSource();
};
CSS codemod:
const postcss = require('postcss');
const renames = {
'--colorPrimary': '--color-primary',
'--color-secondary': '--color-secondary'
};
module.exports = postcss.plugin('refactor-tokens', () => {
return root => {
root.walkDecls(decl => {
// Update property names
if (renames[decl.prop]) {
decl.prop = renames[decl.prop];
}
// Update var() references
Object.entries(renames).forEach(([old, newName]) => {
decl.value = decl.value.replace(
`var(${old})`,
`var(${newName})`
);
});
});
};
});
Codemod distribution:
npx @company/tokens-codemod rename-v2 ./src
How can refactoring verify equivalence?
Verification ensures refactoring does not change visual output.
Value comparison:
function verifyEquivalence(oldTokens, newTokens, mapping) {
const mismatches = [];
Object.entries(mapping).forEach(([oldName, newName]) => {
const oldValue = getResolvedValue(oldTokens, oldName);
const newValue = getResolvedValue(newTokens, newName);
if (oldValue !== newValue) {
mismatches.push({ oldName, newName, oldValue, newValue });
}
});
return mismatches;
}
Visual regression testing:
// Run visual tests before and after
test('Token showcase unchanged', async () => {
const screenshot = await takeScreenshot('/token-showcase');
expect(screenshot).toMatchImageSnapshot();
});
Build output comparison:
# Compare CSS output
diff dist/tokens-old.css dist/tokens-new.css
# Should show only expected naming changes, not value changes
Summary
Design token refactoring improves token system architecture while preserving visual output. Common refactoring scenarios include naming convention updates, hierarchy restructuring, and duplicate consolidation. Planning should assess current state, define goals, and phase changes for manageable disruption. Codemods automate consumer updates across applications. Verification through value comparison, visual regression testing, and output comparison ensures refactoring maintains equivalence.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free