Design systems aren’t just about keeping everything looking the same; they’re about making things flexible enough to handle whatever gets thrown at them.
When you’re juggling multiple brands or different use‑cases, a rigid component can feel more limiting than helpful. That’s where tokens, composition, and configuration come in. Tokens let you swap out brand colors and styles without rewriting code, composition gives you building blocks you can remix into new layouts, and configuration keeps all those variations tidy and predictable. Put them together, and suddenly a single component can stretch to fit diverse brands, layouts, and experiences all without breaking from the system.
Let’s look at a typical “Card” component that is designed with all three of these things in mind such that it can support usage across different brands without breaking a sweat.
Setting up the Basic Card Structure
Say our project calls for a simple card. The card has a toggle-able banner that accepts a text string, a thumbnail image, title, description, and a button.

In this article, all examples are written in Vue, but these principles are not Vue specific. They can be used in any design system that builds from components, even native Web Components.
Our component should end up looking something like this:
<template>
<article class="system-card">
<div class="system-card-media">
<span v-if="bannerText" class="system-card-banner">
{{ bannerText }}
</span>
<img :src="imageUrl" :alt="imageAlt" class="system-card-image" />
</div>
<div class="system-card-content">
<h3 class="system-card-title">{{ title }}</h3>
<p class="system-card-description">{{ description }}</p>
<button class="system-card-button">{{ buttonText }}</button>
</div>
</article>
</template>
<script setup>
defineOptions({ name: "SystemCard" });
defineProps({
bannerText: { type: String, default: null },
imageUrl: { type: String, default: "<https://via.placeholder.com/350x150>" },
imageAlt: { type: String, default: "Card Image" },
title: { type: String, default: "Card Title" },
description: {
type: String,
default:
"This is a description of the card content. It provides more details about the card.",
},
buttonText: { type: String, default: "Learn More" },
});
</script>
<style scoped>
.system-card {
background: #fff;
border-radius: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.system-card-media {
display: flex;
flex-direction: column;
}
.system-card-banner {
background-color: #a3533c;
color: #fff;
font-size: 14px;
font-weight: 600;
padding: 4px;
text-align: center;
width: 100%;
}
.system-card-content {
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
/* ... other card styling, like .system-card-button */
</style>
Code language: HTML, XML (xml)
The Card is then used like this:
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/red-rock.jpg"
imageAlt="Red Rocks Amphitheater during a night concert"
title="Red Rocks Park and Amphitheater"
description="There's No Better Place to See The Stars."
buttonText="View Events"
/>Code language: HTML, XML (xml)
Supporting Multiple Brands/Themes with Tokens
At the most basic level, we can modify this card to support different brands or themes through the use of tokens or variables. I will be using CSS Custom Properties (variables) for all examples in this article, but tokens are not limited to just CSS, you can learn more about Design Tokens from the Design Tokens Community Group (which just shipped their first stable version!)
All of our existing markup stays the same, but we need to modify the CSS to use variables for configuration. While we’re at it, we should also look at any duplicate or hard-coded values and convert those to variable as well to maintain clean, reusable code.
Our new style declarations should look like this:
<style scoped>
/* These root variables are likely to be set up in a more global stylesheet */
:root {
--system-card-bg-color: #ffffff;
--system-card-accent-bg-color: #a3533c;
--system-card-accent-text-color: #ffffff;
--system-card-border-radius: 8px;
--system-card-padding: 16px;
--system-card-gap: 8px;
}
.system-card {
background: var(--system-card-bg-color);
border-radius: var(--system-card-border-radius);
display: flex;
flex-direction: column;
overflow: hidden;
}
.system-card-media {
display: flex;
flex-direction: column;
}
.system-card-banner {
background-color: var(--system-card-accent-bg-color);
color: var(--system-card-accent-text-color);
font-size: 14px;
font-weight: 600;
padding: 4px;
text-align: center;
width: 100%;
}
.system-card-content {
padding: var(--system-card-padding);
display: flex;
flex-direction: column;
gap: var(--system-card-gap);
}
...
</style>Code language: HTML, XML (xml)
Now that our component is using tokens, we can create a custom class and assign those tokens new values. Simply by swapping from statically assigned values to dynamic tokens; CSS Custom Properties in this case, we have enabled our card component to support different visual themes.
<SystemCard
class="custom-blue-card"
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium"
description="Look Nature in the Eye."
butonText="Plan Your Visit"
/>Code language: HTML, XML (xml)
.custom-blue-card {
--system-card-accent-bg-color: #328198;
--system-card-accent-text-color: #00070B;
}
Code language: CSS (css)
Alternatively, we could add a new property on the component that assigns a class with new token definitions if we have a known set of themes we want to support:
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium"
description="Look Nature in the Eye."
butonText="Plan Your Visit"
theme="light-blue"
/>
Code language: HTML, XML (xml)
/* These would likely be global overrides in a global stylesheet */
.theme--light-blue {
--system-card-accent-bg-color: #328198;
--system-card-accent-text-color: #00070B;
}
Code language: CSS (css)

Customizing Content with Composable Slots
A description is great, but what if we want to show a list of details instead? In a situation like this we have two options, either maintain unique code for every different variation of the component, or create composable areas within a single component that engineers can write custom code into, in programming these are often referred to as slots.
Taking our code from before:
<template>
<article class="system-card">
<div class="system-card-media">
<span v-if="bannerText" class="system-card-banner">{{ bannerText }}</span>
<img :src="imageUrl" :alt="imageAlt" class="system-card-image" />
</div>
<div class="system-card-content">
<h3 class="system-card-title">{{ title }}</h3>
<p class="system-card-description">{{ description }}</p>
<button class="system-card-button">{{ buttonText }}</button>
</div>
</article>
</template>Code language: HTML, XML (xml)
We can modify our code to replace the .system-card-description element with a slot, we’ll use the name card-details to identify what we expect the contents of this slot to be.
<template>
<article class="system-card">
<div class="system-card-media">
<span v-if="bannerText" class="system-card-banner">{{ bannerText }}</span>
<img :src="imageUrl" :alt="imageAlt" class="system-card-image" />
</div>
<div class="system-card-content">
<h3 class="system-card-title">{{ title }}</h3>
<slot name="card-details" />
<button class="system-card-button">{{ buttonText }}</button>
</div>
</article>
</template>
Code language: HTML, XML (xml)
For the existing cards with a tagline we can simply place the .system-card-description element within the slot to achieve the same result.
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium butonText="Plan Your Visit"
theme="light-blue"
>
<!-- This is our slot -->
<p class="system-card-description">Look Nature in the Eye.</p>
<!-- This is our slot -->
</SystemCard>
Code language: HTML, XML (xml)

By creating a slot however, we’ve now opened up the possibility for custom content within in. The team can now create a snippet of code to display the list of highlights producing a unique variation on the existing component without completely breaking away from the system.
Component usage could then look like this:
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium butonText="Plan Your Visit"
theme="light-blue"
>
<!-- This is our slot -->
<ul class="highlight-list">
<li class="highlight-item">
<p class="highlight-text">Touch Experiences</p>
</li>
<li class="highlight-item">
<p class="highlight-text">Animal Encounters</p>
</li>
<li class="highlight-item">
<p class="highlight-text">Stingray Feedings</p>
</li>
</ul>
<!-- This is our slot -->
</SystemCard>Code language: HTML, XML (xml)
Producing a result like this:

A Note on Keeping Things Organized
The concept of completely free and open slots is likely terrifying to a designer or engineer who is focused on maintaining clean and organized code since now we’re allowing people to add whatever custom work they want to an area.
To avoid this we can provide “ready-made” child components that we would prefer teams use in these areas, whether through a predetermined list of parts that we know consumers will want, or by paying attention to and adopting repeated usage patterns.
In our examples so far we know we want to support system-card-description and a new system-card-list as options for this space; we can create those as smaller components or “partials.” Engineering and design teams can then use those formally adopted and verified options when they fit their needs, and they maintain all of the benefits of using system components over needing to create custom solutions.
Using these partials might look like this:
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium butonText="Plan Your Visit"
theme="light-blue"
>
<!-- This is our slot -->
<SystemCardDescription text="Look Nature in the Eye.">
<!-- This is our slot -->
</SystemCard>
Code language: HTML, XML (xml)
or:
<SystemCard
bannerText="Featured Location"
imageUrl="image/of/shedd-aquarium.jpg"
imageAlt="Underwater tunnel at the Shedd Aquarium"
title="Shedd Aquarium butonText="Plan Your Visit"
theme="light-blue"
>
<!-- This is our slot -->
<SystemCardList items="[array of items]">
<!-- This is our slot -->
</SystemCard>
Code language: HTML, XML (xml)
Extending Configuration and Composability for Further Customization
Using slots and partials for configuration and composition is not limited to single areas within a component either, once you start thinking in this model you can create incredibly flexible components that can support a vast array of different styles and layouts.
Examining our card component through the lenses of composition and configuration we can create a layout like this.

The first thing we need to do is identify what pieces are configurable and what pieces are composable. Configurable elements are typically controlled through attributes, where composable sections are typically slots.
In our case the location of the .card-media__banner can be configurable to either the top or bottom of the image.
As for composition, we’ve taken the entire system-card-content area and turned it into a slot, allowing users of the component to build out whatever layout meets their needs. In this case we’re putting the button first, followed by the title, a list of details, and social links..
The component code now looks like this:
<template>
<article class="system-card">
<CardMedia
:bannerText="bannerText"
:bannerLocation="bannerLocation"
:imageUrl="imageUrl"
:imageAlt="imageAlt"
/>
<div class="system-card-content">
<slot name="card-content" />
</div>
</article>
</template>
<script setup>
import CardMedia from "./partials/CardMedia.vue";
defineOptions({ name: "SystemCard" });
defineProps({
bannerText: { type: String, default: null },
bannerLocation: { type: String, default: "top" },
imageUrl: { type: String, default: "<https://via.placeholder.com/350x150>" },
imageAlt: { type: String, default: "Card Image" },
title: { type: String, default: "Card Title" },
description: {
type: String,
default:
"This is a description of the card content. It provides more details about the card.",
},
buttonText: { type: String, default: "Learn More" },
});
</script>
Code language: HTML, XML (xml)
and in use:
<SystemCard
bannerText="Escape to the Stars"
bannerLocation="bottom"
imageUrl="image/of/adler-planetarium.jpg"
imageAlt="Aerial view or Adler Planetarium"
>
<SystemButton type="filled" text="Join Us" iconEnd="arrow-right" />
<SystemCardTitle text="Adler Planetarium" />
<SystemCardList
title="Upcoming Events and Shows"
items="[array of items]">
<SystemCardSocials
facebook="link.to.social"
twitter="link.to.social"
youtube="link.to.social"
instagram="link.to.social"
/>
</SystemCardList>
</SystemCard>Code language: HTML, XML (xml)
We’ve moved the banner and image to a new partial we’re importing called CardMedia that partial is then passed the prop bannerLocation and determines whether the banner should appear on the top of bottom of the image. Now, because our entire content area is a slot we’ve added multiple elements as children of the SystemCard; we’ve got a SystemButton, SystemCardTitle, SystemCardSocial, and our SystemCardList from before, in a new layout that we have defined ourselves all while continuing to use the design system without breaking.
Our final result is a highly adaptable card that supports all of our examples through the use of configuration through props and configuration through custom slots.

Turning Principles into Practice
Supporting multiple brands and use‑cases doesn’t have to mean duplicating components or maintaining endless forks of code. By grounding your system in tokens, composition, and configuration, you can keep one core component flexible enough to handle divergent needs.
- Tokens: Centralize design decisions like color, spacing, and typography so brand shifts are a matter of swapping variables or themes, not rewriting CSS.
- Composition (slots/partials): Create structured areas where teams can plug in approved variations, reducing the need for custom one‑offs while still allowing an escape hatch when needed.
- Configuration (props/attributes): Expose common and repeated options for styles, layouts, and behavior so components adapt without breaking consistency.
The payoff is huge: fewer bespoke components to maintain, faster delivery across brands, and a system that scales without losing cohesion. Instead of fighting divergence, you’re designing for it, and that’s how systems stay resilient in the real world.