{"id":8041,"date":"2025-12-19T11:59:44","date_gmt":"2025-12-19T16:59:44","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=8041"},"modified":"2025-12-19T11:59:45","modified_gmt":"2025-12-19T16:59:45","slug":"exploring-multi-brand-systems-with-tokens-and-composability","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/exploring-multi-brand-systems-with-tokens-and-composability\/","title":{"rendered":"Exploring Multi-Brand Systems with Tokens and Composability"},"content":{"rendered":"\n<p>Design systems aren\u2019t just about keeping everything looking the same; they\u2019re about making things flexible enough to handle whatever gets thrown at them. <\/p>\n\n\n\n<p>When you\u2019re juggling multiple brands or different use\u2011cases, a rigid component can feel more limiting than helpful. That\u2019s where <strong><em>tokens<\/em>, <em>composition<\/em>, and <em>configuration<\/em><\/strong> 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.<\/p>\n\n\n\n<p>Let&#8217;s look at a typical &#8220;Card&#8221; 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.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Setting up the Basic Card Structure<\/strong><\/h2>\n\n\n\n<p>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.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"746\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image6.png?resize=732%2C746&#038;ssl=1\" alt=\"A card showcasing Red Rocks Park and Amphitheatre with a featured location banner, a vibrant image of a concert, title, description, and a button inviting users to view events.\" class=\"wp-image-8051\" style=\"aspect-ratio:0.9812434141201265;width:375px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image6.png?w=732&amp;ssl=1 732w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image6.png?resize=294%2C300&amp;ssl=1 294w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"learn-more\">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.<\/p>\n\n\n\n<p>Our component should end up looking something like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-media\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"bannerText\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-banner\"<\/span>&gt;<\/span>\n        {{ bannerText }}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"imageUrl\"<\/span> <span class=\"hljs-attr\">:alt<\/span>=<span class=\"hljs-string\">\"imageAlt\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-image\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-content\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-title\"<\/span>&gt;<\/span>{{ title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-description\"<\/span>&gt;<\/span>{{ description }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-button\"<\/span>&gt;<\/span>{{ buttonText }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">setup<\/span>&gt;<\/span><span class=\"actionscript\">\ndefineOptions({ name: <span class=\"hljs-string\">\"SystemCard\"<\/span> });\n\ndefineProps({\n  bannerText: { type: String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-literal\">null<\/span> },\n  imageUrl: { type: String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">\"&lt;https:\/\/via.placeholder.com\/350x150&gt;\"<\/span> },\n  imageAlt: { type: String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">\"Card Image\"<\/span> },\n  title: { type: String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">\"Card Title\"<\/span> },\n  description: {\n    type: String,\n    <span class=\"hljs-keyword\">default<\/span>:\n      <span class=\"hljs-string\">\"This is a description of the card content. It provides more details about the card.\"<\/span>,\n  },\n  buttonText: { type: String, <span class=\"hljs-keyword\">default<\/span>: <span class=\"hljs-string\">\"Learn More\"<\/span> },\n});\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span> <span class=\"hljs-attr\">scoped<\/span>&gt;<\/span><span class=\"css\">\n<span class=\"hljs-selector-class\">.system-card<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n  <span class=\"hljs-attribute\">overflow<\/span>: hidden;\n}\n\n<span class=\"hljs-selector-class\">.system-card-media<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n}\n\n<span class=\"hljs-selector-class\">.system-card-banner<\/span> {\n  <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-number\">#a3533c<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#fff<\/span>;\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">14px<\/span>;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">600<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">text-align<\/span>: center;\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.system-card-content<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">16px<\/span>;\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-number\">8px<\/span>;\n}\n\n<span class=\"hljs-comment\">\/* ... other card styling, like .system-card-button *\/<\/span>\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The Card is then used like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span>\n\u00a0 <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/red-rock.jpg\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Red Rocks Amphitheater during a night concert\"<\/span>\n\u00a0 <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Red Rocks Park and Amphitheater\"<\/span>\n\u00a0 <span class=\"hljs-attr\">description<\/span>=<span class=\"hljs-string\">\"There's No Better Place to See The Stars.\"<\/span>\n\u00a0 <span class=\"hljs-attr\">buttonText<\/span>=<span class=\"hljs-string\">\"View Events\"<\/span>\n\/&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\"><strong>Supporting Multiple Brands\/Themes with Tokens<\/strong><\/h2>\n\n\n\n<p>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 <a href=\"https:\/\/www.w3.org\/community\/design-tokens\/\">Design Tokens Community Group<\/a> (which just shipped their <a href=\"https:\/\/www.w3.org\/community\/design-tokens\/2025\/10\/28\/design-tokens-specification-reaches-first-stable-version\/\">first stable version<\/a>!)<\/p>\n\n\n\n<p>All of our existing markup stays the same, but we need to modify the CSS to use variables for configuration. While we\u2019re 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.<\/p>\n\n\n\n<p>Our new style declarations should look like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span> <span class=\"hljs-attr\">scoped<\/span>&gt;<\/span><span class=\"css\">\n<span class=\"hljs-comment\">\/* These root variables are likely to be set up in a more global stylesheet *\/<\/span>\n<span class=\"hljs-selector-pseudo\">:root<\/span> {\n  <span class=\"hljs-attribute\">--system-card-bg-color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n  <span class=\"hljs-attribute\">--system-card-accent-bg-color<\/span>: <span class=\"hljs-number\">#a3533c<\/span>;\n  <span class=\"hljs-attribute\">--system-card-accent-text-color<\/span>: <span class=\"hljs-number\">#ffffff<\/span>;\n\n  <span class=\"hljs-attribute\">--system-card-border-radius<\/span>: <span class=\"hljs-number\">8px<\/span>;\n  <span class=\"hljs-attribute\">--system-card-padding<\/span>: <span class=\"hljs-number\">16px<\/span>;\n  <span class=\"hljs-attribute\">--system-card-gap<\/span>: <span class=\"hljs-number\">8px<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.system-card<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-bg-color);\n  <span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-border-radius);\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n  <span class=\"hljs-attribute\">overflow<\/span>: hidden;\n}\n\n<span class=\"hljs-selector-class\">.system-card-media<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n}\n\n<span class=\"hljs-selector-class\">.system-card-banner<\/span> {\n  <span class=\"hljs-attribute\">background-color<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-accent-bg-color);\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-accent-text-color);\n  <span class=\"hljs-attribute\">font-size<\/span>: <span class=\"hljs-number\">14px<\/span>;\n  <span class=\"hljs-attribute\">font-weight<\/span>: <span class=\"hljs-number\">600<\/span>;\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-number\">4px<\/span>;\n  <span class=\"hljs-attribute\">text-align<\/span>: center;\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.system-card-content<\/span> {\n  <span class=\"hljs-attribute\">padding<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-padding);\n  <span class=\"hljs-attribute\">display<\/span>: flex;\n  <span class=\"hljs-attribute\">flex-direction<\/span>: column;\n  <span class=\"hljs-attribute\">gap<\/span>: <span class=\"hljs-built_in\">var<\/span>(--system-card-gap);\n}\n...\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>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.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span>\n\u00a0 <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"custom-blue-card\"<\/span>\n\u00a0 <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span>\n\u00a0 <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium\"<\/span>\n\u00a0 <span class=\"hljs-attr\">description<\/span>=<span class=\"hljs-string\">\"Look Nature in the Eye.\"<\/span>\n\u00a0 <span class=\"hljs-attr\">butonText<\/span>=<span class=\"hljs-string\">\"Plan Your Visit\"<\/span>\n\/&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.custom-blue-card<\/span> {\n<\/span><\/span><mark class='shcb-loc'><span>\u00a0 <span class=\"hljs-attribute\">--system-card-accent-bg-color<\/span>: <span class=\"hljs-number\">#328198<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>\u00a0 <span class=\"hljs-attribute\">--system-card-accent-text-color<\/span>: <span class=\"hljs-number\">#00070B<\/span>;\n<\/span><\/mark><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>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:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">description<\/span>=<span class=\"hljs-string\">\"Look Nature in the Eye.\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">butonText<\/span>=<span class=\"hljs-string\">\"Plan Your Visit\"<\/span><\/span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-tag\">\u00a0 <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"light-blue\"<\/span><\/span>\n<\/span><\/mark><span class='shcb-loc'><span><span class=\"hljs-tag\">\/&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-comment\">\/* These would likely be global overrides in a global stylesheet *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.theme--light-blue<\/span> {\n<\/span><\/span><mark class='shcb-loc'><span>\u00a0 <span class=\"hljs-attribute\">--system-card-accent-bg-color<\/span>: <span class=\"hljs-number\">#328198<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>\u00a0 <span class=\"hljs-attribute\">--system-card-accent-text-color<\/span>: <span class=\"hljs-number\">#00070B<\/span>;\n<\/span><\/mark><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"746\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image3.png?resize=732%2C746&#038;ssl=1\" alt=\"Card displaying Shedd Aquarium with a featured location banner, an underwater scene, title 'Shedd Aquarium', description 'Look Nature in the Eye.' and a button 'Plan Your Visit'.\" class=\"wp-image-8055\" style=\"aspect-ratio:0.9812474224303146;width:399px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image3.png?w=732&amp;ssl=1 732w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image3.png?resize=294%2C300&amp;ssl=1 294w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Customizing Content with Composable Slots<\/strong><\/h2>\n\n\n\n<p>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 <em>slots<\/em>.<\/p>\n\n\n\n<p>Taking our code from before:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-media\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"bannerText\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-banner\"<\/span>&gt;<\/span>{{ bannerText }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"imageUrl\"<\/span> <span class=\"hljs-attr\">:alt<\/span>=<span class=\"hljs-string\">\"imageAlt\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-image\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-content\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-title\"<\/span>&gt;<\/span>{{ title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-description\"<\/span>&gt;<\/span>{{ description }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-button\"<\/span>&gt;<\/span>{{ buttonText }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We can modify our code to replace the <code>.system-card-description<\/code> element with a slot, we\u2019ll use the name card-details to identify what we expect the contents of this slot to be.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-media\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">v-if<\/span>=<span class=\"hljs-string\">\"bannerText\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-banner\"<\/span>&gt;<\/span>{{ bannerText }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">:src<\/span>=<span class=\"hljs-string\">\"imageUrl\"<\/span> <span class=\"hljs-attr\">:alt<\/span>=<span class=\"hljs-string\">\"imageAlt\"<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-image\"<\/span> \/&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-content\"<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-title\"<\/span>&gt;<\/span>{{ title }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">slot<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"card-details\"<\/span> \/&gt;<\/span>\n<\/span><\/mark><span class='shcb-loc'><span>      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-button\"<\/span>&gt;<\/span>{{ buttonText }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>For the existing cards with a tagline we can simply place the <code>.system-card-description<\/code> element within the slot to achieve the same result.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium  butonText=\"<\/span><span class=\"hljs-attr\">Plan<\/span> <span class=\"hljs-attr\">Your<\/span> <span class=\"hljs-attr\">Visit<\/span>\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"light-blue\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&gt;<\/span>\n<\/span><\/span><mark class='shcb-loc'><span><span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/mark><mark class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-description\"<\/span>&gt;<\/span>Look Nature in the Eye.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n<\/span><\/mark><mark class='shcb-loc'><span><span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/mark><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCard<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"746\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image1.png?resize=732%2C746&#038;ssl=1\" alt=\"A card component showcasing the Shedd Aquarium with a featured location banner, an underwater scene, and a call-to-action button.\" class=\"wp-image-8056\" style=\"aspect-ratio:0.9812474224303146;width:378px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image1.png?w=732&amp;ssl=1 732w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image1.png?resize=294%2C300&amp;ssl=1 294w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/figure>\n<\/div>\n\n\n<p>By creating a slot however, we\u2019ve 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.<\/p>\n\n\n\n<p>Component usage could then look like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span>\n\u00a0 <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span>\n\u00a0 <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span>\n\u00a0 <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium\u00a0\u00a0butonText=\"<\/span><span class=\"hljs-attr\">Plan<\/span> <span class=\"hljs-attr\">Your<\/span> <span class=\"hljs-attr\">Visit<\/span>\"\n\u00a0 <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"light-blue\"<\/span>\n&gt;<\/span>\n\u00a0 <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n\u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-list\"<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-item\"<\/span>&gt;<\/span>\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-text\"<\/span>&gt;<\/span>Touch Experiences<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-item\"<\/span>&gt;<\/span>\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-text\"<\/span>&gt;<\/span>Animal Encounters<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-item\"<\/span>&gt;<\/span>\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"highlight-text\"<\/span>&gt;<\/span>Stingray Feedings<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n\u00a0 <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCard<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Producing a result like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"842\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image2.png?resize=732%2C842&#038;ssl=1\" alt=\"A card design showcasing the Shedd Aquarium with a featured location banner, an underwater scene, and a list of available experiences including 'Touch Experiences', 'Animal Encounters', and 'Stringray Feedings'. Below, there is a button labeled 'Plan Your Visit'.\" class=\"wp-image-8057\" style=\"aspect-ratio:0.8693633667196836;width:373px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image2.png?w=732&amp;ssl=1 732w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image2.png?resize=261%2C300&amp;ssl=1 261w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>A Note on Keeping Things Organized<\/strong><\/h3>\n\n\n\n<p>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\u2019re allowing people to add whatever custom work they want to an area.<\/p>\n\n\n\n<p>To avoid this we can provide \u201cready-made\u201d child components that we would <em>prefer<\/em> 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.<\/p>\n\n\n\n<p>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 \u201cpartials.\u201d 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.<\/p>\n\n\n\n<p>Using these partials might look like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium  butonText=\"<\/span><span class=\"hljs-attr\">Plan<\/span> <span class=\"hljs-attr\">Your<\/span> <span class=\"hljs-attr\">Visit<\/span>\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"light-blue\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCardDescription<\/span> <span class=\"hljs-attr\">text<\/span>=<span class=\"hljs-string\">\"Look Nature in the Eye.\"<\/span>&gt;<\/span>\n<\/span><\/mark><span class='shcb-loc'><span>  <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCard<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>or:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Featured Location\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/shedd-aquarium.jpg\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Underwater tunnel at the Shedd Aquarium\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Shedd Aquarium  butonText=\"<\/span><span class=\"hljs-attr\">Plan<\/span> <span class=\"hljs-attr\">Your<\/span> <span class=\"hljs-attr\">Visit<\/span>\"<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">  <span class=\"hljs-attr\">theme<\/span>=<span class=\"hljs-string\">\"light-blue\"<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCardList<\/span> <span class=\"hljs-attr\">items<\/span>=<span class=\"hljs-string\">\"&#91;array of items]\"<\/span>&gt;<\/span>\n<\/span><\/mark><span class='shcb-loc'><span>  <span class=\"hljs-comment\">&lt;!-- This is our slot --&gt;<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCard<\/span>&gt;<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\"><strong>Extending Configuration and Composability for Further Customization<\/strong><\/h2>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>Examining our card component through the lenses of composition and configuration we can create a layout like this.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"732\" height=\"942\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image5.png?resize=732%2C942&#038;ssl=1\" alt=\"An aerial view of the Adler Planetarium showcasing its unique dome structure and surrounding landscape, featuring a prominent banner reading 'Escape to the Stars'. Below, there is a section displaying the title 'Adler Planetarium' and a list of upcoming events.\" class=\"wp-image-8058\" style=\"aspect-ratio:0.7770840137557395;width:408px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image5.png?w=732&amp;ssl=1 732w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image5.png?resize=233%2C300&amp;ssl=1 233w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/figure>\n<\/div>\n\n\n<p>The first thing we need to do is identify what pieces are <em>configurable<\/em> and what pieces are <em>composable<\/em>. Configurable elements are typically controlled through attributes, where composable sections are typically slots.<\/p>\n\n\n\n<p>In our case the location of the <code>.card-media__banner<\/code> can be configurable to either the top or bottom of the image.<\/p>\n\n\n\n<p>As for composition, we\u2019ve 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&#8217;re putting the button first, followed by the title, a list of details, and social links..<\/p>\n\n\n\n<p>The component code now looks like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CardMedia<\/span>\n      <span class=\"hljs-attr\">:bannerText<\/span>=<span class=\"hljs-string\">\"bannerText\"<\/span>\n      <span class=\"hljs-attr\">:bannerLocation<\/span>=<span class=\"hljs-string\">\"bannerLocation\"<\/span>\n      <span class=\"hljs-attr\">:imageUrl<\/span>=<span class=\"hljs-string\">\"imageUrl\"<\/span>\n      <span class=\"hljs-attr\">:imageAlt<\/span>=<span class=\"hljs-string\">\"imageAlt\"<\/span>\n    \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"system-card-content\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">slot<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"card-content\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">template<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">setup<\/span>&gt;<\/span><span class=\"javascript\">\n<span class=\"hljs-keyword\">import<\/span> CardMedia <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/partials\/CardMedia.vue\"<\/span>;\n\ndefineOptions({ <span class=\"hljs-attr\">name<\/span>: <span class=\"hljs-string\">\"SystemCard\"<\/span> });\n\ndefineProps({\n  <span class=\"hljs-attr\">bannerText<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-literal\">null<\/span> },\n  <span class=\"hljs-attr\">bannerLocation<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-string\">\"top\"<\/span> },\n  <span class=\"hljs-attr\">imageUrl<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-string\">\"&lt;https:\/\/via.placeholder.com\/350x150&gt;\"<\/span> },\n  <span class=\"hljs-attr\">imageAlt<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-string\">\"Card Image\"<\/span> },\n  <span class=\"hljs-attr\">title<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-string\">\"Card Title\"<\/span> },\n  <span class=\"hljs-attr\">description<\/span>: {\n    <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>,\n    <span class=\"hljs-attr\">default<\/span>:\n      <span class=\"hljs-string\">\"This is a description of the card content. It provides more details about the card.\"<\/span>,\n  },\n  <span class=\"hljs-attr\">buttonText<\/span>: { <span class=\"hljs-attr\">type<\/span>: <span class=\"hljs-built_in\">String<\/span>, <span class=\"hljs-attr\">default<\/span>: <span class=\"hljs-string\">\"Learn More\"<\/span> },\n});\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>and in use:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCard<\/span>\n  <span class=\"hljs-attr\">bannerText<\/span>=<span class=\"hljs-string\">\"Escape to the Stars\"<\/span>\n  <span class=\"hljs-attr\">bannerLocation<\/span>=<span class=\"hljs-string\">\"bottom\"<\/span>\n  <span class=\"hljs-attr\">imageUrl<\/span>=<span class=\"hljs-string\">\"image\/of\/adler-planetarium.jpg\"<\/span>\n  <span class=\"hljs-attr\">imageAlt<\/span>=<span class=\"hljs-string\">\"Aerial view or Adler Planetarium\"<\/span>\n&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemButton<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"filled\"<\/span> <span class=\"hljs-attr\">text<\/span>=<span class=\"hljs-string\">\"Join Us\"<\/span> <span class=\"hljs-attr\">iconEnd<\/span>=<span class=\"hljs-string\">\"arrow-right\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCardTitle<\/span> <span class=\"hljs-attr\">text<\/span>=<span class=\"hljs-string\">\"Adler Planetarium\"<\/span> \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCardList<\/span>\n    <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Upcoming Events and Shows\"<\/span>\n    <span class=\"hljs-attr\">items<\/span>=<span class=\"hljs-string\">\"&#91;array of items]\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SystemCardSocials<\/span>\n      <span class=\"hljs-attr\">facebook<\/span>=<span class=\"hljs-string\">\"link.to.social\"<\/span>\n      <span class=\"hljs-attr\">twitter<\/span>=<span class=\"hljs-string\">\"link.to.social\"<\/span>\n      <span class=\"hljs-attr\">youtube<\/span>=<span class=\"hljs-string\">\"link.to.social\"<\/span>\n      <span class=\"hljs-attr\">instagram<\/span>=<span class=\"hljs-string\">\"link.to.social\"<\/span>\n    \/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCardList<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">SystemCard<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We\u2019ve moved the banner and image to a new partial we\u2019re importing called <code>CardMedia<\/code> 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\u2019ve added multiple elements as children of the <code>SystemCard<\/code>; we\u2019ve got a <code>SystemButton<\/code>, <code>SystemCardTitle<\/code>, <code>SystemCardSocial<\/code>, and our <code>SystemCardList<\/code> from before, in a new layout that we have defined ourselves all while continuing to use the design system without breaking.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"436\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?resize=1024%2C436&#038;ssl=1\" alt=\"Three card components showcasing different featured locations with images, titles, descriptions, and action buttons.\" class=\"wp-image-8059\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?resize=1024%2C436&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?resize=300%2C128&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?resize=768%2C327&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?resize=1536%2C655&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/image4.png?w=1999&amp;ssl=1 1999w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\"><strong>Turning Principles into Practice<\/strong><\/h2>\n\n\n\n<p>Supporting multiple brands and use\u2011cases doesn\u2019t have to mean duplicating components or maintaining endless forks of code. By grounding your system in <strong><em>tokens<\/em><\/strong><strong>, <\/strong><strong><em>composition<\/em><\/strong><strong>, and <\/strong><strong><em>configuration<\/em><\/strong>, you can keep one core component flexible enough to handle divergent needs.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tokens<\/strong>: Centralize design decisions like color, spacing, and typography so brand shifts are a matter of swapping variables or themes, not rewriting CSS.<\/li>\n\n\n\n<li><strong>Composition (slots\/partials)<\/strong>: Create structured areas where teams can plug in approved variations, reducing the need for custom one\u2011offs while still allowing an escape hatch when needed.<\/li>\n\n\n\n<li><strong>Configuration (props\/attributes)<\/strong>: Expose common and repeated options for styles, layouts, and behavior so components adapt without breaking consistency.<\/li>\n<\/ul>\n\n\n\n<p>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\u2019re designing for it, and that\u2019s how systems stay resilient in the real world.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Exploring a Card component made hyper flexible though use of easily changeable custom properties, props, and slots.<\/p>\n","protected":false},"author":39,"featured_media":8081,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[24,108,168,36],"class_list":["post-8041","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-design","tag-design-systems","tag-vue","tag-web-components"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2025\/12\/cards-thumb.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=8041"}],"version-history":[{"count":11,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8041\/revisions"}],"predecessor-version":[{"id":8089,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/8041\/revisions\/8089"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/8081"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=8041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=8041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=8041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}