Unlocking the frontend – a call for standardizing component APIs pt.2

julrich

Jonas Ulrich

Posted on March 5, 2024

Unlocking the frontend – a call for standardizing component APIs pt.2

#tldr Why Design Systems, and a more structured approach to frontend engineering in general, might be key to a more shared frontend ecosystem. And how this thought might hit an interesting inflection point rather sooner than later, with the advent of production-ready Web Components as a shared technical standard and foundation for interoperability.

So what are the missing pieces? And how could our latest release, and the accompanying schema tooling open sourced with it, play into this? And what would a blog post be today, without tying it into AI? Buckle in: this will be a long one!

Status Quo

Sometimes, at least to me, the current Status Quo in the frontend world feels more fragmented then ever before. Between Tailwind UI and the likes, CSS-in-JS, and a multitude of (differently) opinionated frameworks fighting for our attention “for all the right reasons”.

Meanwhile, web standards seem to rapidly catch up… with native nesting and @layer in CSS and, to name just two great features we’ve won on that front lately, web components getting Declarative Shadow Dom, the Design Token standard rapidly approaching, React finally merging web component compatibility for React 19 it seems, the list goes on.

Nonetheless, we’re still mostly redoing a lot of work, especially those trying to craft bespoke frontend solutions… and not just hitching their wagon to something like Material UI / MUI, and calling it a day.

Does this have to be so fragmented? Don’t we all, in the end, “just” build interfaces based on HTML, CSS and JavaScript… that happen to mostly run in the browser?


Finding universality
via [GIPHY](https://giphy.com/gifs/q9AgIEA8kKWWI2paHT)

Finding universality

Thinking about it… what actually is universal in components? I’d say: They all have an API. Call it Component Props like React, Vue and Svelte do, or Property Binding in Angular, Variables in Figma, or even the structure of Frontmatter typically found in an 11ty code base.

Currently definition of those structures is dominated by either a backend system / API, leaking a backend view of the world into the implementation, or Figma / Sketch / etc design prototypes which attempt to model them, which can skew the focus into a too visually reductionist direction. Either way, it gets really hard to reuse stuff, because you have to re-adapt your code every time a change occurs. You’re “downstream” from the decisions being made and their resulting changes affecting you; and now imagine how people working with the resulting interfaces on a daily basis must feel 😱.

Why else might this be a problem? It shouldn’t be (solely) developers or designers who own this type of API. And this is where we think Design Systems enter the picture, as they establish a collaborative process of component API creation. Nathan Curtis describes this quite nicely:

A design system aspires to achieve a shared vocabulary between designers and developers. As we build visual style and UI components, we make many decisions about how a feature is composed and configured.

I’d add content editors and select stakeholders to that process. Having enough context matters, especially when creating a Design System. I really liked Eduardo da Silvas article on “Sociotechnical architecture”, and I think it very much applies to the introduction of a Design System into an organization!

When also taking into account the structure of most every headless CMS out there, many of those having themselves adopted a component based approach for their content modeling, you start to notice that there already seems to be something like a standard, and shared way, to express this: JSON!

So why do we still have to chase the ball when creating frontend code? Why reinvent the wheel for every project… painstakingly redefining everything, remapping it to CMS and backend systems, and so forth. Can’t we take more control of this process somehow? And wouldn’t it, as a concern, be better handled in something like a Design System anyways?

So how could such a standard look like?

Enter the world of JSON Schema

As luck would have it, there’s JSON Schema… let me quote their central mission statement:

Build more. Break less. Empower others. JSON Schema enables the confident and reliable use of the JSON data format.

Already embedded deep into quite a few development workflows (either through the Open API standard, where it is used for model definitions, or something like Postman to build APIs collaboratively) this immediately enables safer, greater and more meaningful interactions between frontend engineers, backend engineers and those working on APIs / microservices. It’s also already in use in some Design System tooling (like Knapsack), or behind the scenes in headless CMS systems.

For a more in-depth intro, give Ben a listen on his great video here:


Again: I’m pretty convinced that this layer could be universal!

If, additionally, you decouple the Design System as a rule-based framework for design, component, UI and product creation from specific implementation choices taken for components, or a component library as part of your Design System, the value gets more obvious. You start differentiating between the structure and function of a component, and its implementation. Or even multiple implementations when supporting different frontend technologies simultaneously. A mix of components from different frameworks, or different component libraries inside the same framework, starts to become an implementation detail, while everything stays unified under the umbrella of your Design System.

An idea brewing for quite a while already

As our roots stem from 20 years of agency business, we’ve early on started trying to find ways to reuse frontend code, and better decouple frontend from backend engineers in the process. Back then, for us, this meant integration of independently developed frontend code into (mostly) PHP based backend systems like TYPO3 and WordPress (being an “integrator” was an actual job profile in places, with certifications and everything).

Through integrated templating engines (like Fluid for TYPO3) we started exploring better abstractions for reusable frontend code, and ways that could help map it to a backend system.

While this helped ease integration work, in parallel to that we also started exploring more systematic approaches on the frontend side itself. With the advent of Brad Frost Atomic Design, and tools like Pattern Lab, we started using a more component-centric approach. This included colocating all styling (CSS), behavior (JavaScript) and semantic structure (HTML) for a component, and way better encapsulation as a whole. And most influential for us, it turns out, it meant documenting all our expected variants of a component as JSON data:
https://patternlab.io/docs/overview-of-data/

Pattern Lab start page

This left us with a pretty extensive, reusable frontend component library, as most of the projects at the time had pretty similar base requirements, especially when it comes to creating content-driven websites (I’d argue even more so today).

When finally deciding to end our journey as an agency in 2021, to instead transform to an Open Source, product-led business with kickstartDS, this meant we already had a great starting point and a heap of experience with creating complex, modular and reusable frontend setups (we’ve also built some early Design Systems for German DAX listed enterprises around 2013-2016, for good measure).

The first thing we did was a complete rewrite of our code base, with everything we had learnt so far in mind. We ditched Pattern Lab for Storybook, replaced Handlebars with React (but only for its templating capabilities in JSX, everything still usable as pure HTML), updated all client code to vanilla ES6, but most importantly: we ported all of our existing Pattern Lab components and variants by encoding their data.json files into JSON Schema backed component definitions, or component APIs as we like to call them today.


Brewing


via GIPHY

JSON Schema was something that had accompanied us for quite a while already by then. Back in 2013 we started experimenting with using it to structure data for static site generation. A colleague of mine, over 10 years ago 🤯, even wrote quite a nice (somewhat foreshadowing?) article about it:
https://pascalhertleif.de/artikel/silicon-zucchini/

This also marked our first time experimenting with generation of editor interfaces for content, based on our already existing JSON Schema definitions. Which ultimately lead to the release of our kickstartDS low-code CMS starters, and the tooling behind it, today!

kickstartDS schema tooling

What did we build?

We’ve built out tooling that can take component APIs as JSON Schema definitions, like those used in kickstartDS, and process and convert them to other useful formats.

kickstartDS low-code CMS starters - Connecting a Design System to a CMS just got easier | Product Hunt

What’s a format, you might ask. For us, currently, this can mean one of two things:

  • Development: Mainly pure TypeScript types for your components, and other related, generated output like GraphQL fragments or dereferenced JSON Schemas definitions
  • Integration: Headless CMS configuration; processing and mapping your Design System to the concepts of a specific content authoring solution, like Storyblok

That second part is what enables our CMS starters. They use this to take the Design System for design-system.agency and transform it to respective CMS configuration (for Static CMS, Storyblok and Netlify Create / Stackbit as of today) that can be used to start building a website based on such a Design System immediately. Everything demoed with those starters works the same for every Design System built with kickstartDS. To be more precise: it should work with every Design System that decides to encode its component API in JSON Schema. It’s completely generalized!

https://github.com/kickstartDS/schema

And if compatibility with every kickstartDS based Design System is one important dimension of creating the starters and converters, in the process building out the concepts and tooling to make creating connectors easier might actually be the more impactful one. The starters, and their respective connectors, are mainly meant as a demo on how powerful a strong JSON Schema-backed Design System can be. We hope it inspires others to build their own like-minded integrations for their (rightfully so) super specific needs. Hopefully our tooling can aid people in implementing those!

But after all… this is still mostly our own silo. This doesn’t unlock any greater effort, yet…


Brewing


via GIPHY

And why might this matter!

I hinted at this in the very intro to this lengthy post. Web Components seem to be leaving behind their growing pains. With Declarative Shadow DOM arriving, one of the last missing pieces seems to finally complete the picture there.

With React (it seems) finally moving to support everything needed (they are the last major framework lagging behind substantially), too, we might be moving to a world post-framework discussions, and real interoperability on a technical level. I think Jake Lazaroff motivates this beautifully with his articles “Web Components Eliminate JavaScript Framework Lock-in” and “The Web Component Success Story”.

Brad Frost also recently wrote about his dream of a global Design System, and Web Components play a vital role there, too:

Given the above principles, I think it would make sense for the Global Design System to be a library of Web Components. Web Components are part of the web platform and are interoperable (in theory at least) with any web-based tech stack.

In another great article of his, “The Design System Ecosystem”, you’d probably recognize it when he talks about the “core design system”. And some frameworks, like Astro, experiment with similar ideas about composition and collaboration, irrespective of specific frameworks, already.

If you now couple this with a shared way of documenting features and properties for shareable components (🗣️ JSON Schema), you can truly unlock the compositional potential the frontend should have.

We actually think people should build their own tailored casings around different component libraries, frameworks, and standards as they see fit for their requirements, there should be no lock-in:

  • Design: Connect your Design Tokens to a MUI theme to cover for your backoffice dashboards, or to Figma to enable a better designer-developer-workflow
  • Implementation: Integrate specialist libraries for specific requirements, like we do with Bedrock Layout Primitives for layout needs in kickstartDS itself
  • Structure: Use JSON Schema to add structure for interoperability with other systems and integrations (referencing could bridge and connect different systems through URIs)
  • Content: Use our kickstartDS Content module to fill gaps in your coverage of modern content page requirements

Add automation to leverage all of that to automatically, or at least more easily, connect and integrate your adopting systems. kickstartDS was built with those assumptions deeply embedded, and can serve as a great starting point to achieving the same for your Design System!


Reverse


via GIPHY

A call to reverse roles

When building a Design System as described, you invest effort upfront, and justifiably so. If done right, this should not become a throwaway product. It shouldn’t die with a rebrand or redesign… or the change of CMS / backend. In my opinion it should be even more long-lived than every other aspect of your digital toolchain. Especially with the rise in composable and MACH architectures it will be increasingly important to have such a cornerstone in place.

How you interface with your users, customers or editors as a business should not be dependent on technological decisions. Only changes to your organization, or its embedded processes, should necessitate changes to your technical approach and ultimately the stuff you build, not the other way around.

And if your business, or some of your use cases, change or expand, having it set up like this can dramatically reduce the effort needed to reflect those changes downstream in your stack. A change of CMS for a some of your editors can be as easy as switching the integration you use.

This way we can realize the true potential of Design Systems, as the stabilizing core of your digital ecosystem.


Reverse


via GIPHY

How this relates to AI

There’s a lot of buzz around AI in Design Systems currently (to be fair: this is probably the case for every imaginable niche out there).

With tools like Hermae (your custom Design System assistant) or Magic Patterns (your copilot for UI creation) launching, packaging existing ideas and workflows into an easy-to-digest form factor, while others like Jonathan of Roboto Studio show how this can also work by just using the right IDE, there’s still a lot of finger-crossing and LLM-wrestling involved when working with the results.

In the end, someone has to define what your org needs, and how its processes look like. AI can’t (I mean: it shouldn’t) do that. This is where you can use the human element to your advantage, as leverage for (generative) AI. If you know what you need, and you should have made sure that you do (remember the article I mentioned earlier about “Sociotechnical architecture”), encode it in a way that it can also be used for guided generation / Gen AI!

And I think “just” Markdown doesn’t quite cut it for safe guidance. For example: directly generating content for your components. But I’m really excited about tooling like outlines appearing, with a greater focus on guided generation for structured data. Because this is often what we actually need!

Taking outlines: as a coder you could easily plug your Design Systems JSON Schema into it… immediately getting complete safety on the data being generated actually being compatible to your component APIs. Or you could opt for .json, by the authors of outlines, to use the same capabilities through their API, even without deeper technical knowledge.

This is the strength we see in JSON Schema as a guiding factor in structured generation, good docs automatically serving as semantic context for the AI model / LLM.


Reverse


via GIPHY

Looking forward

What does this mean for us? We’ll keep a good eye on Web Components, as this seems like the next evolution to go through. Replacing our React templates with pure Web Components, gaining even more framework-independence, seems like a pretty sure thing to happen.
We’ll also keep exploring ways of content generation, using tools like outlines. We already have encoded the concepts of website settings, content pages and blog posts into JSON Schema, powering our CMS integrations today. It would be a logical next step, to have guided content-generation, independent of headless CMS in use: “Please draft me content for a page about our upcoming release, use our Design System components for guidance”.

We also foresee a need for better general migration support (e.g. when changing a component in a breaking release), and ways of more flexibly mapping / connecting data to component APIs, or gluing together different component APIs for compatibility (e.g. when integrating with third party libraries).

And in general, I sincerely believe that at the intersection of Web Components and JSON Schema lies the potential to unlock the full power of a shared frontend ecosystem!

What do you think? Let me know on Twitter at @tsnmp or Bluesky at @tsnm.bsky.social. You can also connect with me on LinkedIn here!

Or join our community on Discord: https://discord.gg/mwKzD5gejY

💖 💪 🙅 🚩
julrich
Jonas Ulrich

Posted on March 5, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related