CodeWithYou

CloudScape Design with NextJS

Published on
Authors
node

What is Cloudscape?

Cloudscape Design System is an open source solution for building intuitive, engaging, and inclusive user experiences at scale. Cloudscape consists of an extensive set of guidelines to create web applications, along with the design resources and front-end components to streamline implementation. Cloudscape was built for and is used by Amazon Web Services (AWS) products and services. They created it in 2016 to improve the user experience across web applications owned by AWS services, and also to help teams implement those applications faster.

You can read more about Cloudscape here.

It's a beautiful design system and offers a lot in terms of component functionality out of the box. I would highly encourage everyone to try it out.

Installing Cloudscape

For NextJS users, you can install Cloudscape by running the following command:

npm install @cloudscape-design/global-styles @cloudscape-design/components
Advertisement

CloudScape Integration with NextJS

Next, we will need to integrate them into our application. First we will import the CloudScape global styles package into our app. Let's do this in our pages/_app.{jsx,tsx} file

import '@cloudscape-design/global-styles'

After we have included our global styles, let's try to use some of the components in our application.

import { useState } from 'react'
import Header from '@cloudscape-design/components/header'
import Container from '@cloudscape-design/components/container'
import SpaceBetween from '@cloudscape-design/components/space-between'
import Input from '@cloudscape-design/components/input'
import Button from '@cloudscape-design/components/button'

export default function Home() {
  const [value, setValue] = useState('')

  return (
    <SpaceBetween size="m">
      <Header variant="h1">Hello World!</Header>

      <Container>
        <SpaceBetween size="s">
          <span>Start editing to see some magic happen</span>
          <Input value={value} onChange={(event) => setValue(event.detail.value)} />
          <Button variant="primary">Click me</Button>
        </SpaceBetween>
      </Container>
    </SpaceBetween>
  )
}

Run it and see what happens.

Error

This error occurs due to NextJS implementing native CSS modules. We can fix this by use a NextJS plugin to transpile our styles into native CSS modules that NextJS can understand

npm install -D next-transpile-modules next-compose-plugins

After install the plugin, we need edit next.config.js as follows:

const withTranspileModules = require('next-transpile-modules')
const withPlugins = require('next-compose-plugins')

const nextConfig = {
  // other config options
}

// Here we will add a plugin to our configuration to transpile the CloudScape components into
module.exports = withPlugins([withTranspileModules(['@cloudscape-design/components'])], nextConfig)

Bonus, in case you are using typescript then the file next.config.js should be like this

const withTM = require('next-transpile-modules')(['@cloudscape-design/components']);

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
}

const buildConfig = _phase => {
  const plugins = [withTM]
  const config = plugins.reduce((acc, next) => next(acc), {
    ...nextConfig
  })
  return config
}

module.exports = buildConfig();

Restart NextJS dev server we should no longer see any error messages. You also see the following output:

Success

Wow, it seem to work! But wait a second, some error messages are still showing up in console.

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
    at InternalContainer (webpack-internal:///./node_modules/@cloudscape-design/components/container/internal.js:32:21)
    at Container (webpack-internal:///./node_modules/@cloudscape-design/components/container/index.js:24:17)

This is because Cloudscape uses the useLayoutEffect hook to render the components. And the useLayoutEffect hook is not supported in the server renderer. The Cloudscape team does not intend to Replace useLayoutEffect at the moment. You can read more about it here.

To fix this issue, you can add this into _app.js.

import React from 'react'
if (typeof window === 'undefined') React.useLayoutEffect = () => {}

That all, we are good to go! The code is now working as expected.

Thanks for reading! Hope you find this useful! :)

Code available on GitHub

Advertisement