[{"data":1,"prerenderedAt":433},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-building-design-system-react-web-components-i18n-slugs":134,"language-blog-slug-en-building-design-system-react-web-components":141},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135,138],{"locale":136,"value":137},"en","building-design-system-react-web-components",{"locale":139,"value":140},"nl","design-system-bouwen-react-webcomponenten",{"page":142},{"slug":137,"i18nSlugs":143,"social":146,"title":147,"subtitle":79,"isArchived":151,"headerIllustration":152,"date":157,"authors":158,"introTitle":175,"items":176,"pivots":371,"relatedBlogPosts":387,"tags":402,"onMountedScript":161,"onUnmountedScript":161},[144,145],{"locale":136,"value":137},{"locale":139,"value":140},{"title":147,"description":148,"image":149},"Building a Design System with React Web Components","Learn how to create a universal Design system with React and Web Components to use in any web application or framework.",{"url":150},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687161534-linkedin-post-1.jpg",false,{"url":153,"alt":154,"width":155,"height":156},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686922189-design_system_web_components-1.svg",null,455,425,"2023-06-19T02:00:00.000+02:00",[159,167],{"name":160,"lastName":161,"slug":162,"image":163},"Jasper","","jasper",{"url":164,"alt":154,"width":165,"height":166},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535518-jasper.jpg",1892,2523,{"name":168,"lastName":169,"slug":170,"image":171},"Sjoerd","Beentjes","sjoerd",{"url":172,"alt":154,"width":173,"height":174},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534892-sjoerd.jpg",1637,2182,"What if you could build a universal Design system with React and use it in any web application or framework? We achieved this by compiling React to Web Components. This is how.",[177,181,185,195,198,203,206,210,213,216,220,222,225,228,231,235,239,243,250,253,256,259,262,265,268,272,277,280,283,286,289,292,295,299,303,310,313,316,319,322,325,328,331,335,341,343,346,349,353,360,367],{"__typename":178,"id":179,"title":161,"body":180},"TextSectionRecord","133138413","\u003Cp>\u003Cspan style=\"font-weight: 400;\">For a customer&rsquo;s \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fservices\u002Fdesign-system\u002F\">design system\u003C\u002Fa> we needed a universal solution to author its components once and use them in different web applications built with different web frameworks. Our idea was straightforward: author the components in one framework - React - and use a combination of wrappers, polyfills and tooling to make them work in every context. The implementation turned out tougher than we anticipated. But we&rsquo;re happy with the result and happy to share what we learned in the process.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":182,"title":183,"body":184},"133138414","The concept","\u003Cp>\u003Cspan style=\"font-weight: 400;\">In our blog post \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fhow-to-select-framework-design-system-components\u002F\">\u003Cspan style=\"font-weight: 400;\">How to select a framework for design system components\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\"> we described different concepts to create universal components, one of them using React. In a nutshell: we author components in React (.tsx files) and compile them to Web Components using wrappers (.wc.ts files) combined with \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fpreactjs\u002Fpreact-custom-element\" target=\"_blank\" rel=\"noopener\">\u003Cspan style=\"font-weight: 400;\">Preact Custom Element\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\">. This makes the design system available as React components for React applications and Web Components for all other applications:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":187,"image":188,"caption":193,"fullWidth":151,"captionPosition":194},"ImageRecord","133138415",{"url":189,"alt":190,"width":191,"height":192},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686736834-image8.png","A diagram showing how React components and web components can be combined",1752,1999,"Develop components using React and also compile them to Web Components using a Preact wrapper ","bottom",{"__typename":178,"id":196,"title":161,"body":197},"133183051","\u003Cp>\u003Cspan style=\"font-weight: 400;\">We&rsquo;ll focus on the Web Components making the design system universally available. Let&rsquo;s dive a bit deeper into how this concept works. First off, \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fpreactjs.com\u002Fguide\u002Fv10\u002Fswitching-to-preact\u002F\" target=\"_blank\" rel=\"noopener\">\u003Cspan style=\"font-weight: 400;\">Preact can replace React\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\"> and has two notable benefits: &ldquo;Preact's tiny size and standards-first approach make it \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fpreactjs.com\u002Fguide\u002Fv10\u002Fweb-components\u002F\" target=\"_blank\" rel=\"noopener\">\u003Cspan style=\"font-weight: 400;\">a great choice for building web components\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\">&rdquo;. Since a design system typically doesn&rsquo;t need the bells and whistles React may provide, Preact is a great option for us.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Substituting React with Preact can be achieved using tooling configuration like in Vite, Rollup or a package.json:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":200,"language":201,"body":202},"CodeBlockRecord","133183109","json","{\n  ...\n  \"alias\": {\n    \"react\": \"preact\u002Fcompat\",\n    \"react-dom\": \"preact\u002Fcompat\",\n    \"react\u002Fjsx-runtime\": \"preact\u002Fjsx-runtime\"\n  },\n  ...\n}",{"__typename":178,"id":204,"title":161,"body":205},"133183141","\u003Cp>\u003Cspan style=\"font-weight: 400;\">With Preact configured we can now turn a React component into a Web Component. We&rsquo;ll bundle all related files in a directory. Take for example a component to display an alert message to the user:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":207,"language":208,"body":209},"133196688","txt","components\u002Falert\u002F\n    alert.tsx    ← React component\n    alert.css    ← component styles\n    alert.wc.ts  ← Web Component wrapper",{"__typename":178,"id":211,"title":161,"body":212},"133196689","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Note: We always use Typescript to author design systems to provide the best experience for developers consuming the design systems packages. But to keep our examples simple and concise we&rsquo;ve left out their typings. We&rsquo;ll&nbsp; also call our example design system ACME and use `acme` as a prefix everywhere.&nbsp;\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":214,"title":161,"body":215},"133196753","\u003Cp>\u003Cspan style=\"font-weight: 400;\">alert.tsx - author component using React:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":217,"language":218,"body":219},"133196754","js","\u002F\u002F alert.tsx\nimport '.\u002Falert.css’\n\nconst Alert = ({ children, type = ‘info’ }) => (\n  \u003Cdiv className={`\n    alert \n    alert--type-${ type }\n  `}>\n    { children }\n  \u003C\u002Fdiv>\n)",{"__typename":178,"id":221,"title":161,"body":161},"133196782",{"__typename":178,"id":223,"title":161,"body":224},"133196783","\u003Cp>\u003Cspan style=\"font-weight: 400;\">alert.wc.ts - register React component as Web Component using \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fpreactjs\u002Fpreact-custom-element\">\u003Cspan style=\"font-weight: 400;\">Preact Custom Element\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\">:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":226,"language":218,"body":227},"133196786","\u002F\u002F alert.wc.ts:\nimport register from 'preact-custom-element'\nimport Alert from ‘.\u002FAlert.tsx’\n\nregister(Alert, 'acme-alert’, [‘type’], { shadow: true })",{"__typename":178,"id":229,"title":161,"body":230},"133196787","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Use as Web Component in any HTML page or other framework:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":232,"language":233,"body":234},"133196788","html","\u003C!-- in any HTML page: -->\n\u003Cacme-alert type=”warning”>My message.\u003C\u002Facme-alert>",{"__typename":178,"id":236,"title":237,"body":238},"133196794","The reality","\u003Cp>\u003Cspan style=\"font-weight: 400;\">When we started building our components, we quickly came to the conclusion that preact-custom-element does not fit our needs. It appears to be designed to build standalone (web) components, whereas we want to build a system of components that can include styles and interact with each other. To achieve this we customised preact-custom-element and added functionality to support event handling and include styling.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":240,"title":241,"body":242},"133196797","Adding support for event handling","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Because our components function as building blocks, we want them to be able to communicate with each other. Attributes are already converted to props by preact-custom-element, but we also need to communicate the other way around:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":244,"image":245,"caption":161,"fullWidth":151,"captionPosition":194},"133197458",{"url":246,"alt":247,"width":248,"height":249},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686742123-image5.png","Diagram showing in the current 'preact-custom-element' no events are emitted, while in our adapted preact-custom-element this is possible",856,454,{"__typename":178,"id":251,"title":161,"body":252},"133197496","\u003Cp>\u003Cspan style=\"font-weight: 400;\">For example we want to add a dismiss button to our alert component:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":254,"language":218,"body":255},"133197497","\u002F\u002F alert.tsx\nimport '.\u002Falert.css’\n\nconst Alert = ({ children, type = ‘info’, onDismiss }) => (\n  \u003Cdiv className={`\n    alert \n    alert--type-${type}\n  `}>\n     { children }\n\t   \u003Cbutton type=”button” onClick={onDismiss}>\n        Dismiss\n     \u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n)",{"__typename":178,"id":257,"title":161,"body":258},"133197498","\u003Cp>\u003Cspan style=\"font-weight: 400;\">To make this work we added a configuration option called eventNames:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":260,"language":218,"body":261},"133197499","\u002F\u002F alert.wc.ts:\nimport register from '@acme\u002Fregister'\nimport Alert from ‘.\u002FAlert.tsx’\n\nregister({\n  component: Alert,\n  tagName: 'acme-alert',\n  propNames: [‘type'],\n  eventNames: ['onDismiss'],\n  shadow: true,\n});\n",{"__typename":178,"id":263,"title":161,"body":264},"133197503","\u003Cp>\u003Cspan style=\"font-weight: 400;\">The way this works is that we create a proxy function for these callbacks, which will emit a custom event when this function is called. The name of this custom event is generated from the value passed to eventNames. In our case &lsquo;onDismiss&rsquo; becomes &lsquo;acme-dismiss&rsquo;. This is a custom event name to prevent conflicts with bubbling events from the web component, which are different from the events emit. With this change we now support event handling and it can be used like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":266,"language":233,"body":267},"133197504","\u002F\u002F anywhere\n\u003Cacme-alert type=”warning”>My message.\u003C\u002Facme-alert>\n\u003Cscript>\ndocument.querySelector(‘acme-alert’)\n  .addEventListener(‘acme-dismiss’, (event) => ...)\n\u003C\u002Fscript>",{"__typename":178,"id":269,"title":270,"body":271},"133197505","Adding support to include styles","\u003Cp>\u003Cspan style=\"font-weight: 400;\">The web components we build should not be polluted by existing styles on a page as we want our design system components to be usable anywhere. While preact-custom-element supports enabling Shadow DOM to keep out unwanted styles, it doesn&rsquo;t provide a way to include the styles we do want. So we further customised our preact-custom-element helper:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":273,"image":274,"caption":161,"fullWidth":151,"captionPosition":194},"133292881",{"url":275,"alt":276,"width":248,"height":249},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686745142-image2.png","A diagram that shows that the original preact-custom-element can not inject styles, while our custom solution is able to do it",{"__typename":178,"id":278,"title":161,"body":279},"133292882","\u003Cp>\u003Cspan style=\"font-weight: 400;\">We allow registering a new Web Component with a list of inlined styles:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":281,"language":218,"body":282},"133292883","\u002F\u002F alert.wc.ts:\nimport register from '@acme\u002Fregister'\nimport Alert from ‘.\u002FAlert.tsx’\nimport alertStyles from '.\u002Falert.css?inline'\n\nregister({\n  component: Alert,\n  tagName: 'acme-alert',\n  propNames: [‘type'],\n  eventNames: ['onDismiss'],\n  styles: [alertStyles],\n  shadow: true,\n});",{"__typename":178,"id":284,"title":161,"body":285},"133292884","\u003Cp>\u003Cspan style=\"font-weight: 400;\">While our example component only has a single stylesheet, other components may depend on multiple stylesheets like an input component requiring input and (shared) label styles. Stylesheets that are required by all components in the design system (like reset styles) are included within the register helper itself, so they don&rsquo;t have to be registered in every individual component. Within the register helper all styles are combined into a \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fweb.dev\u002Fconstructable-stylesheets\u002F\" target=\"_blank\" rel=\"noopener\">\u003Cspan style=\"font-weight: 400;\">Constructible Stylesheet\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\">. It looks something like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":287,"language":218,"body":288},"133292885","\u002F\u002F handling styles inside @acme\u002Fregister:\nconst sheets = [\n  resetStyles,\n  otherHelperStyles,\n  ...this.styles, \u002F\u002F passed via register\n].map((styles) => {\n  const sheet = new CSSStyleSheet();\n  sheet.replaceSync(styles);\n  return sheet;\n});\n\nthis.root.adoptedStyleSheets = sheets;",{"__typename":178,"id":290,"title":161,"body":291},"133292976","\u003Cp>\u003Cspan style=\"font-weight: 400;\">As support for \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FCSSStyleSheet#browser_compatibility\" target=\"_blank\" rel=\"noopener\">\u003Cspan style=\"font-weight: 400;\">Constructible Stylesheets in Safari is currently experimental\u003C\u002Fspan>\u003C\u002Fa>\u003Cspan style=\"font-weight: 400;\">, this requires a polyfill for now:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":293,"language":218,"body":294},"133292977","import 'construct-style-sheets-polyfill'",{"__typename":178,"id":296,"title":297,"body":298},"133292987","The optimisation","\u003Cp>\u003Cspan style=\"font-weight: 400;\">At this point our React components successfully compile to Web Components, so we could stop here. But as we always strive to deliver high performance projects, we still have work to do.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":300,"title":301,"body":302},"133292991","An app provider for shared JS dependencies","\u003Cp>\u003Cspan style=\"font-weight: 400;\">With our working setup each component bundles its own Preact runtime. And while at 4kb minified and gzipped Preact is tiny in comparison to React&rsquo;s 45kb (core + DOM), it still adds up when we have dozens of components.\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">Bundling Preact in every component has the upside that every component can function in isolation. It also means that if a team implements ten of our components, they would add 40kb (gzipped) to their bundle. This extra bundle size just consists of ten times the same instance of Preact. Time to optimise this!\u003C\u002Fspan>\u003C\u002Fp>\n\u003Cp>\u003Cspan style=\"font-weight: 400;\">To solve this we created an '\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">app-provider'\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">&nbsp;that imports Preact once and makes it available to all its child components:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":304,"image":305,"caption":161,"fullWidth":151,"captionPosition":194},"133294821",{"url":306,"alt":307,"width":308,"height":309},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686745402-image1.png","A diagram that shows how in the optimized situation dependencies are shared between components, instead of being bundled with each of them",857,378,{"__typename":178,"id":311,"title":161,"body":312},"133294822","\u003Cp>\u003Cspan style=\"font-weight: 400;\">We can use it like this:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":314,"language":233,"body":315},"133294823","\u002F\u002F provider loads and exposes Preact\n\u003Cacme-app-provider>\n  \u003Cacme-component-a>...\u003C\u002Facme-component-a>\n  \u003Cacme-component-b>...\u003C\u002Facme-component-b>\n  \u003Cacme-component-c>...\u003C\u002Facme-component-c>\n\u003C\u002Facme-app-provider>",{"__typename":178,"id":317,"title":161,"body":318},"133372925","\u003Cp>\u003Cspan style=\"font-weight: 400;\">The '\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\">app-provider'\u003C\u002Fspan>\u003Cspan style=\"font-weight: 400;\"> imports React and ReactDOM (which are being aliased to Preact, as described above) and attaches it to the window object. We prefix it with our library name to rule out the possibility that it conflicts with existing properties.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":320,"language":218,"body":321},"133372926","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport { register } from '@acme\u002Fregister'\n\n\u002F\u002F we also include other shared dependencies, like:\nimport 'construct-style-sheets-polyfill'\n\nwindow.__ACME__React = React\nwindow.__ACME__ReactDOM = ReactDOM\n\nconst AppProvider = ({ children }) => {\n  return \u003C>{children}\u003C\u002F>\n}\n\nregister({\n  component: AppProvider,\n  tagName: ‘acme-app-provider'\n  options: { shadow: true },\n})",{"__typename":178,"id":323,"title":161,"body":324},"133372932","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Since we&rsquo;ve configured aliases for React to Preact the app provider actually bundles Preact. Finally the (Rollup) build for all other components is configured to use the globally exposed React(DOM):\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":199,"id":326,"language":218,"body":327},"133372933","return {\n  output: {\n  format: 'iife',\n  \u002F\u002F add an exception for our app-provider, as\n  \u002F\u002F it provides React instead of consuming it\n  ...(!isAppProvider && {\n    globals: {\n      'react': '__ACME__React',\n      'react-dom': '__ACME__ReactDOM',\n    },\n  }),\n  \u002F\u002F ...\n}",{"__typename":178,"id":329,"title":161,"body":330},"133372934","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Now all components nested within the app provider share a single version of each JS dependency. \u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":332,"title":333,"body":334},"133374045","A theme provider for shared CSS","\u003Cp>\u003Cspan style=\"font-weight: 400;\">The Shadow DOM prevents us from sharing common CSS between components the same way we do for JS dependencies. However all our design system tokens - defined as custom CSS properties - can pass the Shadow DOM. We therefore extract these custom CSS properties from all components and make them available through a single shared theme provider:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":336,"image":337,"caption":161,"fullWidth":151,"captionPosition":194},"133374046",{"url":338,"alt":339,"width":248,"height":340},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686746289-image6.png","A diagram that shows how in the optimized situation CSS variables are shared between components, instead of being bundled with each of them",366,{"__typename":178,"id":342,"title":161,"body":312},"133374047",{"__typename":199,"id":344,"language":233,"body":345},"133374048","\u002F\u002F provider includes and exposes CSS variables:\n\u003Cacme-theme-provider>\n  \u003Cacme-component-a>...\u003C\u002Facme-component-a>\n  \u003Cacme-component-b>...\u003C\u002Facme-component-b>\n  \u003Cacme-component-c>...\u003C\u002Facme-component-c>\n\u003C\u002Facme-theme-provider>",{"__typename":178,"id":347,"title":161,"body":348},"133374049","\u003Cp>\u003Cspan style=\"font-weight: 400;\">An extra benefit of this theme provider is that we can more easily add a light\u002Fdark theme switch in the future.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":178,"id":350,"title":351,"body":352},"133374052","Optimising CSS class names","\u003Cp>\u003Cspan style=\"font-weight: 400;\">There&rsquo;s one more thing we want to optimise: CSS class names. We value clear naming of our components and all their parts, especially in a design system. While this is important in development and documentation we prioritise end user experience in production. And for production these class names can be anything as they&rsquo;re scoped and can&rsquo;t have conflicts. As long class names bloat the HTML and stylesheets, we decided to minimise them for production, saving roughly another 5% of the total bundle size of our design system.\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":186,"id":354,"image":355,"caption":359,"fullWidth":151,"captionPosition":194},"133430884",{"url":356,"alt":357,"width":191,"height":358},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686749028-screenshot-2023-06-14-at-15-20-16.png","DOM tree showing expanded web components",1006,"In development: long class names conveying meaning",{"__typename":186,"id":361,"image":362,"caption":366,"fullWidth":151,"captionPosition":194},"133430885",{"url":363,"alt":357,"width":364,"height":365},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1686749113-screenshot-2023-06-14-at-15-23-06.png",1730,950,"In production: efficient class names saving 5% bundle size",{"__typename":178,"id":368,"title":369,"body":370},"133430895","Wrapping up","\u003Cp>\u003Cspan style=\"font-weight: 400;\">Putting it all together we now have a \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fservices\u002Fdesign-system\u002F\" title=\"design system\">design system\u003C\u002Fa> with components that can be used anywhere. We have a custom compiler to turn React components into Web Components with support for scoped styling and event handling. And we&rsquo;ve extended our setup with a shared app and theme provider to optimise the bundle size of our design system.\u003C\u002Fspan>\u003C\u002Fp>",[372],{"title":373,"body":374,"links":375,"mailchimpValue":161,"mailchimpName":161,"mailchimpId":161,"formType":383,"contactPerson":384},"Need help with your design system?","\u003Cp>See what we can do for your digital product.\u003C\u002Fp>\n",[376],{"__typename":377,"id":378,"title":379,"link":380},"InternalLinkRecord","135155038","Read about our service",{"__typename":381,"slug":382},"ServiceRecord","design-system","none",{"name":160,"lastName":161,"jobTitle":385,"image":386},"CTO, Co-founder",{"url":164,"alt":154,"width":165,"height":166},[388,395],{"slug":389,"title":390,"date":391,"authors":392},"how-to-select-framework-design-system-components","How to select a framework for design system components","2022-12-12T01:00:00.000+01:00",[393],{"name":160,"image":394},{"url":164,"alt":154,"width":165,"height":166},{"slug":396,"title":397,"date":398,"authors":399},"kick-start-your-design-system-with-a-design-inventory-workshop","Kick-start your Design System with a Design Inventory Workshop","2021-09-16T02:00:00.000+02:00",[400],{"name":160,"image":401},{"url":164,"alt":154,"width":165,"height":166},[403],{"id":404,"title":405,"slug":406,"blogPosts":407},"JBiZUe8mQVujxlNVR5gx8Q","Design Systems","design-systems",[408,415,422],{"slug":409,"title":410,"date":411,"authors":412},"accessibility-in-design-systems","Accessibility in Design Systems","2025-06-17T14:15:56.000+02:00",[413],{"name":168,"image":414},{"url":172,"alt":154,"width":173,"height":174},{"slug":416,"title":417,"date":418,"authors":419},"design-system-from-scratch-from-the-shelf","Design System: from scratch or from the shelf?","2024-11-19T13:16:02.759+01:00",[420],{"name":160,"image":421},{"url":164,"alt":154,"width":165,"height":166},{"slug":423,"title":424,"date":425,"authors":426},"write-components-once-run-everywhere-with-mitosis-a-beautiful-dream-or-reality","“Write components once, run everywhere” with Mitosis; a beautiful dream or reality?","2024-09-16T13:04:31.307+02:00",[427],{"name":428,"image":429},"Wessel",{"url":430,"alt":428,"width":431,"height":432},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1721035942-wessel.jpg",2135,2868,1776256139093]