DEV Community

Jamie Barton for Hygraph

Posted on

Make no compromises on content design with GraphQL Union Types

Designers are often given a hard time by developers on their their wild design aesthetics and how difficult it is to translate pixels into HTML.

Developers often cut corners leaving designers enraged that the final piece in production looks nothing like it did during the design phase! I've done this before.🙈

Thankfully we've moved on from using tables to create our 3 column layout and images as borders, oh what a time to be alive.

Then same can be said about developers and marketing, or content teams specifically. Most out of the box Content Management Systems give you a set way of building things, and provide additional attributes or meta you can tag onto content entries to make your wild designs "work".

Often all of this leads to more code to maintain and more ways for things to go wrong. It's also just damn right unnecessary thanks to Headless APIs.

We at GraphCMS like to do things a little differently. We don't provide any content models out of the box but instead give you a schema editor to design how your content should be structured.

The real power of this is you can now create and connect content models to work with your wild designs, and one of the biggest benefits of using GraphQL is the native Union Types.

 Content types

  • Heros
  • Gallery
  • Testimonial
  • Grid
  • CTAs
  • and much more...!

Now it's not uncommon for these content types to appear more than once on a page, and ordered.

Using GraphCMS we can define each of these content models and connect them using relations, and thanks to the power of GraphQL, working with this data is even easier.

Consider a Page model:

GraphCMS Page Model

The Page model itself is pretty bare bones, and is only used in a way to query the specific page we need, but using the references field type in GraphCMS, we can connect multiple other models.

We've called these Blocks but they could be named Sections or ContentBlocks, that's up to you!

An example of one of these "Blocks" is Hero. The Hero model contains its own fields.

GraphCMS Hero Model


Querying a GraphQL Union Type

Let's imagine we have some data in our project, and we want to get the a Page by slug that is home in our GraphQL query.

The query will look a little something like this:

query PageQuery($slug: String!) {
  page(where: { slug: $slug }) {
    blocks {
      __typename
      ... on Cta {
        content
        title
      }
      ... on Grid {
        columns {
          __typename
          ... on Feature {
            content
            title
          }
        }
      }
      ... on Hero {
        subtitle
        title
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The import thing to note is we use ... to query on a specific GraphQL type. GraphQL types are automatically generated by GraphCMS when you define your content models.

When it comes to implement the design and switching between what "blocks" you should render to the page, we can leave that to the developer.

In the example below we are using React to import all exported "Blocks" from one folder, and then mapping through our blocks array, and depending on the __typename returned from our GraphQL query, we can show the corresponding view.

import * as Blocks from "../components";

function Index({ page }) {
  return (
    <>
      {page.blocks.map((block, index) => {
        const Component = Blocks[block.__typename];

        if (!Component) return null;

        return <Component key={index} {...block} />;
      })}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now for our Hero all that's left to do is create a component and that will be rendered!

function Hero({ subtitle, title }) {
  return (
    <header className="bg-blue-800 py-12 md:py-20 text-center">
      <div className="max-w-4xl mx-auto px-6">
        <h1 className="font-semibold mb-4 text-2xl md:text-4xl text-white">
          {title}
        </h1>
        {subtitle && (
          <h2 className="font-medium text-blue-300 text-lg">{subtitle}</h2>
        )}
      </div>
    </header>
  );
}
Enter fullscreen mode Exit fullscreen mode

So there we have it! We have the data a format that is custom to my project needs, and a way to render these blocks thanks to the __typename value from our GraphQL query.

Here is an example of the finished piece with more content models:

GraphCMS GraphQL Union Types Example


You can get started with this example built by @ynnoj over on GitHub, and try out the queries for yourself using the API Playground.

Top comments (2)

Collapse
 
aarow profile image
aarow

Thanks for the straightforward writeup. A lot of voices say to no longer "compose" pages, but for marketing sites, it seems like a good idea. This is perfect.

Collapse
 
fourwhitesocks profile image
fourwhitesocks

I would LOVE an example of this using SvelteKit!! Please please :)