Static marketing website for open-core software company, with content pulled from a cloud-based CMS

All development

  • web
  • front-end
  • Next.js
  • Prismic
  • Styled Components
  • React
  • Typescript
  • JSX
  • GraphQL
  • Node.js
  • static
  • freelance


Working from an existing partial design, I built a new version of Cesium’s marketing website.

Cesium have been fantastic to work with, and it gives me a great deal of pride that I’m doing work for a company with an open-source product at its core.


In the original brief this site was to be built with Gatsby and Prismic. Around the time of those first discussions I had been reading great things about Next.js, and I was considering suggesting using that instead. Just as I was about to, they suggested it to me!

From the very start, I found Next.js excellent to use. The way I see it, it’s magic in all the areas where I want it to be magic (routing in particular), and it leaves everything to me everywhere else.

It’s fantastic to have the ability to seamlessly have some pages statically built, others build on demand, and then API routes which run as lambdas, all from the same codebase, with no messy configuration.

Having said that, this particular website is 100% static, other than a few dynamic pieces loaded at runtime via external APIs to customize the site to the user, and an API route which enables the content author to preview their changes.

Prismic with Next.js

When I started development, I wasn’t satisfied with the various examples of using Prismic with Next.js I could find. I drew what inspiration I needed to from them, and went my own way.

A particular difficulty was in resolving links. If we had a simple URL scheme, such as /blog/<slug> and /page/<slug> this would be simple. However, we wanted URLs such as /blog/<year>/<month>/<day>/<slug> and /<grandparent-slug>/<parent-slug>/<slug>. In the blog case, determining a document’s URL requires information from a custom field of that document (we can’t use Prismic’s built-in publication date because a lot of legacy blog posts were being entered). Meanwhile, in the page hierarchy case, links to parent documents need to be followed until we reach the root.

Using the GraphQL API, this information can all be retrieved as part of the query for the document which describes the link, as long as we have some finite limit on depth in the case of the hierarchy. However, when a link is present as part of a rich text block, we only get Prismic’s built-in metadata, with no way to query for extra fields at the same time.

All this together means that we can’t resolve links synchronously (which we need) unless we have already preloaded all the required data. As such, the only practical approach was to load minimal metadata for pages and blog posts at the start of the build process. Unfortunately, since Next.js needs the data available in order to hydrate the page on load, this dataset does end up fetched by the visitor.

In future I’d like to see a feature in Prismic’s GraphQL API to request extra data along with rich text links, which would let us avoid this particular inefficiency.

Another problem I hit a few times was with a URL length limit. Prismic’s GraphQL API currently only supports GET requests. In such requests the entire query needs to be in a URL query parameter, and URLs have a maximum length. As I gradually added more “slice” types during development, the queries got longer and longer until finally we started hitting the limit.

The first workaround was to compress the queries – by using a library to remove whitespace and other unnecessary characters from the query we dipped back beneath the limit for a while. Later, once hitting the limit again, I optimized the queries by making use of GraphQL fragments.

Prismic say they do plan to support POST queries; I hope it’s sooner rather than later.



I’m particularly happy with the carousel component of this website. There’s one visual issue I currently can’t think of a solution for (I want a rounded border around the images’ area, but not around each individual image, and I do not want to reorganize the markup; this proves to be very tricky indeed), but other than that I think it’s great: browser-native scrolling and scroll-snapping, fully elastic with no hardcoded sizes, accessible.

Background colours and spacing

I’m also happy with the routine I came up with for batching slices into containers, so that successive slices with the same configured background colour are siblings. This lets us rely on margin collapsing, which is a huge help in making the spacing between elements look natural in all situations, while keeping the styling simple.

Focus styles

I paid special attention to focus styles for accessibility. The design package I was handed did not have focus styles for all elements, and those which did exist were not sufficient in my view.

In the end we went with a thick outline in a bright colour, consistently across almost all interactive components.

I found that the best way to leverage the new :focus-visible pseudo-selector, while remaining backwards-compatible with non-supporting browsers, was to apply the desired focus styles to :focus, and then remove them again on :focus:not(:focus-visible). Under this scheme, non-supporting browsers will apply the focus styles on :focus and ignore the other rule, while supporting browsers will apply the focus styles only on :focus-visible.

Still to come…

There’s more work to be done on the website.

I’m now working on a site-wite search feature, and after that we’ll be moving the Cesium documentation to this Next.js app.