1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7860],{27104:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/blog/2026-06-24-better-together-design-systems-graphql-part-1",function(){return n(20804)}])},20804:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return k},useTOC:function(){return j}});var i=n(52676),s=n(92937),a=n(45043),o=n(79428),r={src:"/_next/static/media/01.1fd3c3d2.png",height:1638,width:1536,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAMAAADz0U65AAAACVBMVEX19vf6+vvq7PDLNo4gAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJ0lEQVR4nFWJQQ4AQBDBWv9/9IY9jZBQQCKBn4B1ISvdKDqy/6rHAwYeACF4FfPUAAAAAElFTkSuQmCC",blurWidth:8,blurHeight:8},h={src:"/_next/static/media/02.98fb3cad.png",height:1126,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAAElBMVEX19vfo5+n5+vvf4ODt7+/RztLKZNZsAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJklEQVR4nB3JwQ0AMAyDQEic/Veu3A9COhh2GUBbyBpN58yXO0sPBU4AQNPoVUYAAAAASUVORK5CYII=",blurWidth:8,blurHeight:5},c={src:"/_next/static/media/03.d8e39a3d.png",height:1224,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAGCAMAAADJ2y/JAAAANlBMVEX3+Pnt8PSvr7Ps7O+xuMDEx83w8fL7/Pzd3uK+wMXUtrSbpq/R0Myvy96CkpvIys+Ns9K+1ODEVPG9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAMUlEQVR4nBXBCRYAEAhAwY9S2d3/sp4ZKO6+vTBPHpGXcGeM1iTAzFJNFRVRvuhdwXgljQEyXUKOegAAAABJRU5ErkJggg==",blurWidth:8,blurHeight:6},l={src:"/_next/static/media/04.232920a1.png",height:1189,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAGCAMAAADJ2y/JAAAAElBMVEXu8PHb3N7h4+Xn6Or2+PrO1NehFHooAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJ0lEQVR4nBXGwQ0AAAiDQGh1/5WN5B4AqkDWxpUmVAszD6Lha9KfAwgTAEgBnwMRAAAAAElFTkSuQmCC",blurWidth:8,blurHeight:6},d={src:"/_next/static/media/05.e0bea3f0.png",height:534,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAADCAMAAACZFr56AAAAD1BMVEX09vjv7e7j5OXr2tjj2dzexfZ3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAHUlEQVR4nBXGsQ0AAAiAMED/v9nYqVRYAOqsvz8HAaIAGXqY9S0AAAAASUVORK5CYII=",blurWidth:8,blurHeight:3},p={src:"/_next/static/media/06.037264d5.png",height:922,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAAKlBMVEXn6evT1dbs7+/09fbZ29zf4OJDRUGoqKmPkI5+fnwwLSvCw8TEw8NzcXFZZ0KgAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAK0lEQVR4nBXEtxEAIBAEsb232P7bZVAgIBSY4z/DGMRMXVGpirM2LeTZ+QAKnACYyxYQcQAAAABJRU5ErkJggg==",blurWidth:8,blurHeight:5},A={src:"/_next/static/media/07.b2596e4f.png",height:893,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAMAAACEE47CAAAAHlBMVEVuaWg7Pj2EfXylnZxTV1ZmYmFZXFtITUx5dHMoLCskIYePAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAJUlEQVR4nB3Jxw0AMBDDMNnX9184QPglsQtU4ElJZzzdmTJR/HoH9ABnmrBBkAAAAABJRU5ErkJggg==",blurWidth:8,blurHeight:4},m={src:"/_next/static/media/08.c227feb0.png",height:801,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAMAAACEE47CAAAABlBMVEXy9Pbp7e+e0idcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAF0lEQVR4nGNgYGBgZGRgZADRYCYCwDgAANAACQI/IqgAAAAASUVORK5CYII=",blurWidth:8,blurHeight:4},g={src:"/_next/static/media/09.e6740a01.png",height:1222,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAGCAMAAADJ2y/JAAAAElBMVEXu8PL8/Pzz9Pb0+Pjc39/p6OpjPcxDAAAAAXRSTlP+GuMHfQAAAAlwSFlzAAALEwAACxMBAJqcGAAAACZJREFUeJwlxsERACAMwzDXCfuvzFH0EknbTuD04AaIgvOE/IWlXgttAFcMBHbNAAAAAElFTkSuQmCC",blurWidth:8,blurHeight:6},u={src:"/_next/static/media/10.03a36220.png",height:1638,width:1456,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAICAMAAAAC2hU0AAAAIVBMVEX29/jx9PXs7/Du7uf8/PzZ3d7k5ujr6tSgoJ/Av8C5u7ywDmxYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAMklEQVR4nBXHwQ3AMAzDQEqynTb7DxyYnwORPL6D3D2/ObFS8KUQ4oiqgtjaz4it2+sDFqAAlMAAW1AAAAAASUVORK5CYII=",blurWidth:7,blurHeight:8},f={src:"/_next/static/media/11.ec27cfc1.png",height:609,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAADCAMAAACZFr56AAAAJFBMVEW3ubhoaWrx9PWoqqZtcHH1+Pn+//8zOzt5eXru7/BDREQtLS3tsrKmAAAAAXRSTlP+GuMHfQAAAAlwSFlzAAALEwAACxMBAJqcGAAAACFJREFUeJxjYOJkYmZkYeRgYOVkY2Zn5+ZiYGViYwCJAAAGJAB0U3ny1wAAAABJRU5ErkJggg==",blurWidth:8,blurHeight:3},w={src:"/_next/static/media/12.3af2f622.png",height:792,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAECAMAAACEE47CAAAAD1BMVEXy9/fx8vT5/fzp7fDc4eAqPxJnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIElEQVR4nC3DgQkAAAjDsHbz/5tFMBCgMw1Y1QQqcN8CA24AIuRtV7IAAAAASUVORK5CYII=",blurWidth:8,blurHeight:4},b={src:"/_next/static/media/13.6d4e247c.png",height:1318,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAGCAMAAADJ2y/JAAAAIVBMVEX29/nj5eXv8/Tn6uv5/P3R1NPo7fLQ396UmZmcvLqcsa8bb9qWAAAACXBIWXMAAAsTAAALEwEAmpwYAAAALElEQVR4nBXBhxEAMAwCsQdsp+w/cC4SYEUC24lUzKird2PrkhPiWaaMWnwPDaUAgvwCy8IAAAAASUVORK5CYII=",blurWidth:8,blurHeight:6},y={src:"/_next/static/media/14.883af72f.png",height:925,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAMAAABPT11nAAAAJ1BMVEX09vj6/P57g4Q0NzhDR0bIysvv8PHX2NpjZWaKi4ydpaa6vL3P0NJNtQnNAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAKklEQVR4nB2KyREAIAyEyLExav/9OvHHAJzuZQAeIauBTFE2JjWF6/s/DwvqAHnzfVXIAAAAAElFTkSuQmCC",blurWidth:8,blurHeight:5},x={src:"/_next/static/media/15.f0a066d0.png",height:595,width:1638,blurDataURL:"data:image/png;
1base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAADCAMAAACZFr56AAAADFBMVEX19/j7/Pzw8fLn6ucv5gi/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAHUlEQVR4nGNgYmJiZgADJiZmJkZGRhCTmYGRkREAAa4AHA8EIzkAAAAASUVORK5CYII=",blurWidth:8,blurHeight:3},v={src:"/_next/static/media/16.021677b3.png",height:706,width:1638,blurDataURL:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAADCAMAAACZFr56AAAADFBMVEX19/jw8/P7/Pzi5eWfDghuAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAG0lEQVR4nGNgYGRkZGQAA0ZGZgYmJgiLgYkJAAD2ABSJxeg6AAAAAElFTkSuQmCC",blurWidth:8,blurHeight:3};function j(e){return[{value:"The GraphQL Double-Edged Sword",id:"the-graphql-double-edged-sword",depth:2},{value:"Context",id:"context",depth:2},{value:"What about Design Systems?",id:"what-about-design-systems",depth:2},{value:"Atomic vs. Pattern Components",id:"atomic-vs-pattern-components",depth:2},{value:"Why only Atomic and Pattern Components?",id:"why-only-atomic-and-pattern-components",depth:2},{value:"Mock Case Study",id:"mock-case-study",depth:2},{value:"UI Divergence at Expedia Group",id:"ui-divergence-at-expedia-group",depth:2},{value:"Current State",id:"current-state",depth:2},{value:"Applying Design System Thinking to GraphQL through Collaborative Workshops",id:"applying-design-system-thinking-to-graphql-through-collaborative-workshops",depth:2},{value:"Atomic Components Schema Storm",id:"atomic-components-schema-storm",depth:2},{value:"Icon Component",id:"icon-component",depth:3},{value:"Link with Icon Component",id:"link-with-icon-component",depth:3},{value:"Co-locate GraphQL Fragments with Atomic Components",id:"co-locate-graphql-fragments-with-atomic-components",depth:2}]}var k=(0,s.c)(function(e){let{toc:t=j(e)}=e,n={a:"a",br:"br",em:"em",h2:"h2",h3:"h3",img:"img",li:"li",ol:"ol",p:"p",strong:"strong",ul:"ul",...(0,o.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:(0,i.jsx)(n.em,{children:"A deep dive into how coupling design system components with GraphQL schema through collaborative cross-functional workshops can reduce sprawl, ensure consistency, and enhance productivity at both the UI and API layers."})}),"\n",(0,i.jsx)(n.h2,{id:t[0].id,children:t[0].value}),"\n",(0,i.jsx)(n.p,{children:"While the supergraph architecture has been a game-changer - enabling the creation of large-scale GraphQL deployments that connect distributed microservices and multiple decoupled frontends - schema governance at scale remains a huge challenge."}),"\n",(0,i.jsx)(n.p,{children:"A big part of this problem is what we call the âGraphQL double-edged sword.â GraphQL makes it really easy to fetch the exact data you want; however, without implementing an intelligent and intentional approach, teams are highly likely to produce duplicate queries and schema - leading to API sprawl - and duplicate or near-duplicate UIs - leading to inefficiency and inconsistent user experiences."}),"\n",(0,i.jsx)(n.p,{children:"This phenomenon is further exacerbated in siloed environments where multiple teams end up shipping similar yet divergent UIs, resulting in inefficiency and inconsistent user experiences. Such UI code sprawl is highly likely to lead to bugs and build up tech debt."}),"\n",(0,i.jsx)(n.p,{children:"In this article, we explore a mock case study to paint a detailed picture of the problem and we hypothesize a radically new approach to cross-functional collaboration on both design systems and GraphQL schema design. This approach puts in place guardrails to prevent duplication while enabling quick iteration on new experiences. These practices aim to guarantee both UI and schema consistency, while protecting against the trap of unwinding bad patterns in production."}),"\n",(0,i.jsx)(n.h2,{id:t[1].id,children:t[1].value}),"\n",(0,i.jsx)(n.p,{children:"Our radically new approach comes out of a particular context and is therefore best for this context. While surely many of our ideas can be applied to other contexts, you should know that what weâre proposing assumes the following:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"We are powering multiple client platforms across multiple business domains."}),"\n",(0,i.jsxs)(n.li,{children:["We leverage the ",(0,i.jsx)(n.a,{href:"https://www.apollographql.com/docs/technotes/TN0032-sdui-basics/",children:"server-driven UI (SDUI)"})," architectural pattern to minimize client-side logic and facilitate consistency between client platforms."]}),"\n",(0,i.jsxs)(n.li,{children:["We use ",(0,i.jsx)(n.a,{href:"https://graphql.org/resources/federation/",children:"GraphQL federation"})," to hydrate clients with data via a unified GraphQL API that aggregates numerous microservices."]}),"\n",(0,i.jsx)(n.li,{children:"We operate in a large organization with many distributed teams."}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:t[2].id,children:t[2].value}),"\n",(0,i.jsxs)(n.p,{children:["As per ",(0,i.jsx)(n.a,{href:"https://www.apollographql.com/docs/technotes/TN0032-sdui-basics/#use-a-design-system",children:"recommended best practices"}),", server-driven UI with GraphQL greatly benefits from the use of a design system."]}),"\n",(0,i.jsx)(n.p,{children:"The problem is that, despite the existence of authoritative resources on design systems in general, the intersection of design systems and GraphQL APIs is still pretty much uncharted territory."}),"\n",(0,i.jsxs)(n.p,{children:["To make things even trickier, what belongs in a design system and what doesnât seems to vary depending on who you ask. Then, thereâs the fact that design systems evolve slower than the products they support, ",(0,i.jsx)(n.a,{href:"https://bigmedium.com/ideas/design-system-pace-layers-slow-fast.html",children:"which is a feature and not a bug"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"While design systems certainly bring enhanced consistency and reduction of boilerplate across organizations, the fact that they are slow to evolve can create bottlenecks in the softw
1are development lifecycle. This is similar to the challenge GraphQL platform teams face trying to push forward the best possible evolution of the federated GraphQL API."}),"\n",(0,i.jsxs)(n.p,{children:["Here is our central question: what if we approached these perceived bottlenecks as opportunities for closer collaboration on schema design that could improve the reusability of both frontend components and the associated ",(0,i.jsx)(n.a,{href:"https://graphql.com/learn/interfaces-and-unions/#fragments",children:"GraphQL fragments"})," and schema?"]}),"\n",(0,i.jsx)(n.h2,{id:t[3].id,children:t[3].value}),"\n",(0,i.jsx)(n.p,{children:"The first step to such closer collaboration requires that we agree on the types of components that exist within our design system, in the context of GraphQL schema design."}),"\n",(0,i.jsxs)(n.p,{children:["Taking the cue from ",(0,i.jsx)(n.a,{href:"https://atomicdesign.bradfrost.com/chapter-2/",children:"Brad Frostâs atomic design methodology"}),", we posit the atomic component as the smallest unit in a design system. For our purposes, letâs define it as follows:"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.em,{children:"An atomic component is a UI component that cannot be broken down into smaller parts and reassembled
1in another way."})}),"\n",(0,i.jsxs)(n.p,{children:["Here are a few examples from the Expedia Group system:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"Five Expedia Group atomic components â Link with Icon, Map, Rating, Icon with Text, and Heading â each showing a design system preview with editable source code",placeholder:"blur",src:r})]}),"\n",(0,i.jsx)(n.p,{children:"However, in contrast to Brad Frostâs hierarchy of atoms, molecules, organisms, templates, and pages, we propose to introduce only one more type of component besides the atomic one, that is, the pattern component. Letâs define it as follows:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.em,{children:"A pattern component is composed of atomic components and built to enable a user to complete a task or solve a problem."})}),"\n",(0,i.jsx)(n.p,{children:"Consider the following examples of Expedia Group pattern components:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Three Expedia Group pattern components: a Global Header navigation bar, a Featured Locations map, and a Loyalty Rewards Activity list",placeholder:"blur",src:h})}),"\n",(0,i.jsxs)(n.p,{children:["Atomic components enable site-wide consistency of UI across business domains and client platforms (both internal ",(0,i.jsx)(n.em,{children:"and"})," customer facing.) By combining these atomic components into pattern components, we unlock user ",(0,i.jsx)(n.em,{children:"experiences"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Note: The user doesnât go to Expedia Group to âclick a buttonâ (an interaction with an atomic component); instead the user goes to Expedia Group to âbook a trip to Las Vegasâ (an interaction with a pattern component)."}),"\n",(0,i.jsx)(n.p,{children:"Thus, atomic components are mechanical realities, while pattern components represent product realities that carry meaning to the user. The differences between these librariesâthe atomic component library and the pattern component libraryâhelps us determine who needs to be at the relevant schema design workshops."}),"\n",(0,i.jsx)(n.h2,{id:t[4].id,children:t[4].value}),"\n",(0,i.jsx)(n.p,{children:"Before we answer this question, letâs first delineate the larger context."}),"\n",(0,i.jsxs)(n.p,{children:["More and more organizations are adopting a ",(0,i.jsx)(n.a,{href:"https://konghq.com/solutions/api-management-graphql",children:"GraphQL-native approach"}),". This unlocks the ability to ",(0,i.jsx)(n.em,{children:"codify"})," the contract between data consumers and data providers. What used to be a polyglot system of BFFs, with unpredictability and a lack of standards between systems, has been modernized and replatformed into massive unified APIs all feeding into a single supergraph endpoint."]}),"\n",(0,i.jsxs)(n.p,{children:["Unified data APIs have unlocked a more intelligent architecture that allows a ",(0,i.jsx)(n.a,{href:"https://www.apollographql.com/docs/technotes/TN0027-demand-oriented-schema-design/",children:"demand-oriented"})," approach. This means that product teams, as well as specific client consumers, can ask for just the data they need."]}),"\n",(0,i.jsx)(n.p,{children:"The demand-oriented approach can be put in practice in a very agile way by using server-driven UIs, meaning that clients (web, iOS, Android) can get updated versions of experiences without having to change a line of code. As the backend data and experience services evolve more functionality, this is immediately available to users across platforms."}),"\n",(0,i.jsx)(n.p,{children:"Whatâs worth noting is that design systems and the new GraphQL-native unified API have much in common: both promote consistency and efficiency across business domains, with design systems focusing on user experience consistency and the unified API on data delivery consistency."}),"\n",(0,i.jsxs)(n.p,{children:["Now, by limiting design systems to just two levels, i.e., atomic and pattern components, we can map design system concepts 1:1 to schema concepts. This means that product-focused design decisions can be ",(0,i.jsx)(n.em,{children:"codified"})," as a data contract between the frontend clients and backend data providers."]}),"\n",(0,i.jsx)(n.p,{children:"We believe that such coupling, together with a simplified design system hierarchy, is going to result in a
1number of benefits."}),"\n",(0,i.jsx)(n.p,{children:"First, limiting to two levels increases the maintainability of the system. Too many layers can result in dependency hell as updates in one layer trigger a ripple of necessary updates across all levels and consumers. This can result in outdated versions of the design system being deployed due to lack of time to address the tech debt to update."}),"\n",(0,i.jsx)(n.p,{children:"Further, atomic componentsâ data requirements can be modeled into shared GraphQL types, easily reusable by backend data service teams to use as building blocks for richer, product-specific user experiences. These combinations of atomic components constitute pattern components."}),"\n",(0,i.jsx)(n.p,{children:"For frontend teams, atomic components can have GraphQL fragments associated with them, for easy reuse across experiences, all without having to reinvent the data shape each time."}),"\n",(0,i.jsx)(n.p,{children:"Moreover, pattern components can be used to delineate query boundaries on a page. Being made up of atomic components, their data structures are easy to assemble from the shared library of schema, similar to how frontend experience teams easily assemble design system atomic components to build UIs."}),"\n",(0,i.jsxs)(n.p,{children:["While it can be tempting to fashion one massive GraphQL query per page, this quickly becomes ",(0,i.jsx)(n.a,{href:"https://youtu.be/4li6JjY5IYU?feature=shared&t=984",children:"a performance problem at scale"}),". Limiting queries to the pattern component level not only makes page performance better, it makes it easier for engineers and designers alike to reason about these components and their queries."]}),"\n",(0,i.jsx)(n.p,{children:"Without a system like this, many very similar queries often emerge, and sometimes whole services and teams are spun up to provide data shapes that already exist in a slightly different format in the graph."}),"\n",(0,i.jsx)(n.h2,{id:t[5].id,children:t[5].value}),"\n",(0,i.jsx)(n.p,{children:"Weâve been fascinated with the evolution of both design systems and unified GraphQL APIs. Letâs now explore a mock case study where we look at some divergence in Expedia Groupâs user interface across product domains, and see what happens when we marry design systems with GraphQL via collaborative cross-functional workshops."}),"\n",(0,i.jsx)(n.h2,{id:t[6].id,children:t[6].value}),"\n",(0,i.jsxs)(n.p,{children:["Below, you can see two variants of a product page at expedia.com; one for a Property and one for an Activity.",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"Side-by-side comparison of a Property Product Overview page (Hyatt Regency La Jolla) and an Activity Product Overview page (La Jolla 2-Hour Kayak Tour) on expedia.com",placeholder:"blur",src:c})]}),"\n",(0,i.jsx)(n.p,{children:"Itâs worth noting that, although these pages are continuously evolving, they were originally created before Expedia Group began adopting its design system and the supergraph. Currently, the teams at Expedia Group are working to consolidate experiences to streamline user interactions, reduce operational complexities, and leverage efficiencies."}),"\n",(0,i.jsx)(n.p,{children:"Such a brownfield scenario means that:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"Both the experiences and the underlying GraphQL layer need to be continuously evolved, rather than rebuilt from scratch;"}),"\n",(0,i.jsx)(n.li,{children:"Given the sheer scale of the organization and the fact that experiences require collaboration between product, design, and engineering functions, we need to put some coordination and planning into place."}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"But how do we pull this off without getting overwhelmed by analysis paralysis so often associated with upfront design?"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"Our north star is a unified, coherent customer experience served by an intelligent architecture"})," which prioritizes reusability and composability, enabling new user experiences to be quickly crafted, tested, and delivered."]}),"\n",(0,i.jsx)(n.p,{children:"Too much variation in similar user experiences across product domains can negatively affect sales as well as dim
1inish productivity for engineers and designers, who may be building duplicative elements due to lack of governance."}),"\n",(0,i.jsxs)(n.p,{children:["With the above in mind, letâs examine the variation in these product overview components and how theyâre being fetched.",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"The Property Overview and Activity Overview components highlighted and compared side by side on Expedia Group product pages",placeholder:"blur",src:l})]}),"\n",(0,i.jsx)(n.h2,{id:t[7].id,children:t[7].value}),"\n",(0,i.jsx)(n.p,{children:"The starting point for unifying the overview component variations should definitely be a discussion between product and design teams. Perhaps one variation aligns more closely with what has been defined at the design system level, or maybe thereâs data indicating superior performance from a UX perspective."}),"\n",(0,i.jsx)(n.p,{children:"Regardless of the particulars, letâs assume that the result of this discussion is an overall preference for the Property variation. From this perspective, we can observe that:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.em,{children:(0,i.jsx)(n.img,{alt:"Annotated comparison of the Property Overview and Activity Overview components with numbered callouts identifying atomic components to reuse or consolidate",placeholder:"blur",src:d})})}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"The âratingsâ atomic component should be reused for consistency."}),"\n",(0,i.jsx)(n.li,{children:"The âfeaturesâ component should follow the âPopular amenitiesâ layout."}),"\n",(0,i.jsx)(n.li,{children:"The âoverviewâ component should be a subheading."}),"\n",(0,i.jsx)(n.li,{children:"The âmapâ atomic component should be reused for consistency."}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"In this scenario, product and design agree with each other that promoting more consistency in the experiences is beneficial. This, of course, affects the UI code and rightly so; by consolidating these components, we can increase reusability and eliminate redundant frontend code."}),"\n",(0,i.jsx)(n.p,{children:"But what about the GraphQL schema? Unsurprisingly, thereâs inconsistency and a lack of reusability here, too. Letâs compare the queries powering the different overview variations side by side:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Three GraphQL queries for the Property, Packages, and Activity overview components shown side by side, color-coded to indicate overlapping fields (green), naming inconsistencies (orange), and problematic schema design (red)",placeholder:"blur",src:p})}),"\n",(0,i.jsx)(n.p,{children:"First, the elements marked green indicate an overlap between the queries which presents an opportunity for either reuse or abstraction. It appears that consolidating these queries into one could be especially low lift in the case of the Property and Packages overview components, since the only issue there is inconsistent naming that causes bloat in the schema (marked orange):"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"guestRating vs. rating"}),"\n",(0,i.jsx)(n.li,{children:"numberOfReviews vs. totalReviews"}),"\n",(0,i.jsx)(n.li,{children:"isRefundable vs. canBeRefunded"}),"\n",(0,i.jsx)(n.li,{children:"amenities { vs. includedAmenities {"}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["In the case of the Activity overview, things become messier. Here, too, we can notice naming inconsistencies causing bloat (orange), but thereâs also a bigger problem (marked red):",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"GraphQL code snippet showing the Activity overview features field with overly constrained sub-fields â policy, timeLength, supportsMobileVoucher, and providesInstantConfirmation â highlighted in red as an example of problematic schema design",placeholder:"blur",src:A})]}),"\n",(0,i.jsx)(n.p,{children:"It seems that fields have been named for each feature. Such a constrained approach doesnât support reusability and calls for a redesign in the schema."}),"\n",(0,i.jsx)(n.p,{children:"Clearly, the task of unifying experiences involves not just the design and frontend code, but also the GraphQL layer. But what if there was a way to simultaneously address both issues and, in the process, implement guardrails to prevent schema bloat and promote reusability?"}),"\n",(0,i.jsx)(n.h2,{id:t[8].id,children:t[8].value}),"\n",(0,i.jsx)(n.p,{children:"Letâs assume that, at the design level, the Property overview component will serve as a blueprint for the consolidated Product overview pattern component that is going to be incorporated into the design system."}),"\n",(0,i.jsx)(n.p,{children:"As we know, every pattern component needs to be powered by atomic components to ensure experience consistency:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Diagram showing the Property Overview pattern component composed of atomic components â Heading, Rating, Icon with Text, Link with Icon, and Map â with a legend distinguishing pattern components from atomic components",placeholder:"blur",src:m})}),"\n",(0,i.jsx)(n.p,{children:"The atomic components are the reusable building blocks de
1signed to form any kind of pattern component or UI recipe that product stakeholders may require. So what if we co-located GraphQL fragments with these atomic components to promote not just frontend code reuse but also query and schema consistency and reuse?"}),"\n",(0,i.jsx)(n.p,{children:"To achieve this, we need to first hold a cross-discipline workshop, where:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsx)(n.li,{children:"we discover and zero in on the demand for data,"}),"\n",(0,i.jsx)(n.li,{children:"all parties agree on consistent naming."}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["The idea for this kind of workshop goes back to ",(0,i.jsx)(n.a,{href:"https://www.youtube.com/watch?v=zsHp6_kJVJ8",children:"Samâs GraphQL Summit talk"})," introducing the concept of ",(0,i.jsx)(n.a,{href:"https://www.xolv.io/blog/articles/introducing-graphql-schema-storming/",children:"schema storming"}),". The gist of this technique lies in collaboratively annotating UI mockups to define data requirements, which greatly facilitates subsequent query and schema design. By incorporating ",(0,i.jsx)(n.a,{href:"https://www.youtube.com/watch?v=4li6JjY5IYU",children:"Amandaâs experience and insights on working with design systems and GraphQL at the enterprise level"}),", we tried to adjust the schema storming format to a large org scenario."]}),"\n",(0,i.jsx)(n.p,{children:"In the following sections, weâre going to explore how these collaborative workshops could possibly help improve a design system, establish intelligent schema governance, consolidate divergent experiences, and prevent tech debt."}),"\n",(0,i.jsx)(n.h2,{id:t[9].id,children:t[9].value}),"\n",(0,i.jsx)(n.p,{children:"Since atomic components are the foundational building blocks of our experiences, we need to bring together key stakeholders from across disciplines. This includes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Designers from the design system team"}),"\n",(0,i.jsx)(n.li,{children:"Engineers from web, iOS, and Android"}),"\n",(0,i.jsx)(n.li,{children:"Members of the GraphQL platform team"}),"\n",(0,i.jsx)(n.li,{children:"Key product managers with cross-org context"}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Often designers, engineers, and product people are only together in the room during all-hands meetings or outages. We are proposing to pre-emptively gather these critical stakeholders and discuss data requirements at even the atomic component level, and codify these learnings into GraphQL schema that serves as the source of truth for the system. Any consumers of these atomic components will, by default, adhere to the guidelines established in the schema storming session."}),"\n",(0,i.jsx)(n.p,{children:"If we collaborate on data requirements early, we avoid fighting similar issues in multiple places (i.e. we only make these decisions once) and we decrease the likelihood of future tech debt."}),"\n",(0,i.jsx)(n.p,{children:"Letâs now try to imagine what the schema storming workshop would look like for the icon with text atomic component."}),"\n",(0,i.jsx)(n.h3,{id:t[10].id,children:t[10].value}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:'The Icon with Text atomic component from the Expedia Group design system, showing a bus icon with the label "The hotel is 1 hour from the airport by bus" and its editable JSX source code',placeholder:"blur",src:g})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"The basic premise of the workshop is really simple."})," Using a whiteboard tool like Miro, the relevant stakeholders need to to discuss the data expectations of the icon component and record them as sticky notes placed on the design system screen cap:"]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Schema storming annotation of the Icon with Text atomic component, with sticky notes labeling the data fields: iconName, text, size, ariaString, and id",placeholder:"blur",src:u})}),"\n",(0,i.jsx)(n.p,{children:"Letâs unpack what they could eventually arrive at:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:["The icon needs a ",(0,i.jsx)(n.strong,{children:"name"})," that maps to one of the icons available in the design system."]}),"\n",(0,i.jsxs)(n.li,{children:["The icon has an accompanying ",(0,i.jsx)(n.strong,{children:"text"}),"."]}),"\n",(0,i.jsxs)(n.li,{children:["The icon has a configurable ",(0,i.jsx)(n.strong,{children:"size."})]}),"\n",(0,i.jsxs)(n.li,{children:["To support visually impaired user experiences, an ",(0,i.jsx)(n.strong,{children:"ariaString"})," is provided for screen readers."]}),"\n",(0,i.jsxs)(n.li,{children:["To support persistence of specific variants in a content management system, an ",(0,i.jsx)(n.strong,{children:"id"})," is provided."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Note that the data requirements concern both the visible elements and the non-visible ones, such as accessibility. At Expedia Group, designers are responsible not only for the visible design but also for the audible design, making them crucial for this atomic component schema storm session."}),"\n",(0,i.jsx)(n.p,{children:"Apart from listing the requirements as sticky notes, this is the time to zero in on the naming of these elements. This is a key element of this exercise. The idea is that if all stakeholders are on the same page about whatâs called what early on, it will protect the teams from inconsistencies and bloat."}),"\n",(0,i.jsx)(n.p,{children:"Letâs assume now that everyone agrees that there are no more stickies to be added here. Having contributed to the UI annotation, the designers can then leave the meeting, because, in the second part of the session, the frontend and backend
1/platform engineers are going to get particular about the type definitions."}),"\n",(0,i.jsxs)(n.p,{children:["Essentially, they need to discuss the return types and nullability of the various fields. In this case, the âIcon with Textâ UI component only requires fields with scalar return types, and all types are required, so the work of creating the schema (in SDL form) is easy. A graph relationship naturally forms and is easy to express as a reusable type definition in GraphQLâs Schema Definition Language (SDL).",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.em,{children:(0,i.jsx)(n.img,{alt:"Diagram mapping the Icon with Text component's sticky note annotations to a GraphQL SDL type definition: type IconWithText with fields id, iconName, text, size, and ariaString",placeholder:"blur",src:f})})]}),"\n",(0,i.jsx)(n.h3,{id:t[11].id,children:t[11].value}),"\n",(0,i.jsxs)(n.p,{children:["Letâs now explore another atomic component schema storm example, this time for the link with an icon component.",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"The Link with Icon atomic component from the Expedia Group design system, showing two example links with arrow icons and the component description",placeholder:"blur",src:w}),(0,i.jsx)(n.br,{}),"\n","Again, we start by gathering the right people to discuss the data requirements and record them as sticky notes."]}),"\n",(0,i.jsxs)(n.p,{children:["With links, thereâs much more than meets the eye:",(0,i.jsx)(n.br,{}),"\n",(0,i.jsx)(n.img,{alt:"Schema storming annotation of the Link with Icon atomic component, with sticky notes labeling data fields: icon, text, uri, iconPosition (with LEADING/TRAILING options), and analytics fields including referrerId, linkName, eventType, CLICK, and IMPRESSION",placeholder:"blur",src:b})]}),"\n",(0,i.jsx)(n.p,{children:"Note that this time, in addition to design and engineering stakeholders, we likely need someone from product to align on the analytics part."}),"\n",(0,i.jsx)(n.p,{children:"Similar to the previous example, the engineering stakeholders should eventually arrive at an SDL expression of reusable type and enum definitions."}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Diagram mapping the Link with Icon component's annotations to GraphQL SDL type definitions for enums IconPosition and AnalyticEventType, and types Analytics and LinkWithIcon, with arrows connecting sticky notes to their corresponding schema fields",placeholder:"blur",src:y})}),"\n",(0,i.jsx)(n.p,{children:"Ultimately, the GraphQL types defined in these atomic component schema storming sessions should be incorporated into a shared schema library for consumption by backend experience teams. Diligence in defining visible content, accessibility, analytics, and configuration requirements at the atomic component level ensures that all of these aspects are integrated into the shared schema library. As a result, thereâs no need to reinvent these requirements each time the teams build something."}),"\n",(0,i.jsx)(n.p,{children:"Backend teams can now develop with confidence knowing that when they use an atomic component they will not be missing critical elements required for consistent UX across platforms."}),"\n",(0,i.jsx)(n.h2,{id:t[12].id,children:t[12].value}),"\n",(0,i.jsx)(n.p,{children:"Type definitions feeding the shared schema library are just one part of the equation. On the frontend, we still need to define GraphQL fragments and co-locate them with the atomic components in the design system code library."}),"\n",(0,i.jsx)(n.p,{children:"Hereâs what this could look like for the âIcon with Textâ and âLink with Iconâ atomic components:"}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Diagram showing the Icon with Text atomic component mapped to a co-located GraphQL client fragment with fields id, iconName, text, size, and ariaString",placeholder:"blur",src:x})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.img,{alt:"Diagram showing the Link with Icon atomic component mapped to a co-located GraphQL client fragment with fields text, icon, iconPosition, uri, and analytics including referrerId, linkName, and eventType",placeholder:"blur",src:v})}),"\n",(0,i.jsx)(n.p,{children:"While this may seem like a lot of work to do for each atomic component, itâs fairly easy to plan and iterate on, one component at a time."}),"\n",(0,i.jsx)(n.p,{children:"Meanwhile, the resulting wins are immense:"}),"\n",(0,i.jsxs)(n.ol,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"The frontend developer experience is greatly enhanced"})," during the process of composing pattern components because all atomic component schema requirements come for free from the design system."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"We"})," ",(0,i.jsx)(n.strong,{children:"decrease the chance that developers add unneeded GraphQL types"}),"; because schemas are frequently very large, developers often add types without first looking to see if the needed type already exists. This leads to duplication and frequently undesired variation."]}),"\n",(0,i.jsxs)(n.li,{children:["We ",(0,i.jsx)(n.strong,{children:"reduce the chance of over/under-fetching"}
1)," because each GraphQL fragment is associated directly and only with the component it supports. (This is as opposed to a common practice which is to write and maintain a GraphQL fragment without reference to the specific component it supports. Making this worse, this fragment frequently supports more than one component, each which has different needs, so as we update data to support one component we forget about the other component and create over/under-fetching in the other component.)"]}),"\n",(0,i.jsxs)(n.li,{children:["Coupling data with the component it powers ",(0,i.jsx)(n.strong,{children:"surfaces downstream effects at the right time"}),": if a data field is removed from a GraphQL fragment, it will be clear that the UI element which displays that data also needs to be removed. Conversely, if a UI element is added to the component, it will be clear that a data field to support that element needs to be added."]}),"\n",(0,i.jsxs)(n.li,{children:["We can ",(0,i.jsx)(n.strong,{children:"more-easily fuel design mocks for pattern components"}),", because the majority of data requirements are already known before a fully-fledged design is even produced."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"We no longer have to repeatedly wrestle with accessibility, analytics, and configuration."})," All too often these requirements surface as bugs in production. Shifting these concerns left lets us figure it out once, and then repeatedly reuse."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"The above wins are all made possible by attaching data requirements to the atomic design system components. But to actually realize these wins in production, we need to compose these data-aware atomic components into larger experiences, which we call pattern components."}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"/blog/2026-06-25-better-together-design-systems-graphql-part-2/",children:"Join us in Part 2"})," to see how to put this into action!"]}),"\n",(0,i.jsx)(n.p,{children:"â---"})]})},"/blog/2026-06-24-better-together-design-systems-graphql-part-1",{filePath:"src/pages/blog/2026-06-24-better-together-design-systems-graphql-part-1/index.mdx",timestamp:1789481543e3,pageMap:a.v,frontMatter:{title:"Better Together: Cross-Functional Collaboration at the Intersection of Design Systems and GraphQL APIs - Part 1 of 2",tags:["blog"],date:"2026-06-24",byline:"Amanda Olsen, Sam Combs",featured:!0},title:"Better Together: Cross-Functional Collaboration at the Intersection of Design Systems and GraphQL APIs - Part 1 of 2"},"undefined"==typeof RemoteContent?j:RemoteContent.useTOC)}},function(e){e.O(0,[3556,5043,2888,9774,179],function(){return e(e.s=27104)}),_N_E=e.O()}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.