Multi-brand React component library for Møller
@gnist/design-system
is a React component library containing reusable, multi-brand GUI building blocks for applications in the Møller ecosystem.
For instructions on developing components, see the Development docs.
Consuming the library
The library is published as @gnist/design-system
in the public npm registry. The prefix @moller
is an npm scope associated with our organization on npm
Installing the library
Run the command
npm install @gnist/design-system @gnist/themes
Using the library
To use the library, the vanilla-extract plugin needs to be used.
Vite
For Vite, you need
npm install -D @vanilla-extract/vite-plugin @vanilla-extract/esbuild-plugin
Your vite.config.ts
might look like this:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin";
import { vanillaExtractPlugin as veEsbuildPlugin } from "@vanilla-extract/esbuild-plugin";
export default defineConfig({
plugins: [react(), vanillaExtractPlugin()],
optimizeDeps: {
esbuildOptions: {
plugins: [veEsbuildPlugin({ runtime: true })],
},
},
});
In the application entrypoint, import the required global styles and choose a theme
import { LocalizationProvider } from "@gnist/design-system";
import { bilholdLight } from "@gnist/themes/themes/bilholdLight.css.js";
import { gumpen } from "@gnist/themes/themes/gumpen.css.js";
import { brandless } from "@gnist/themes/themes/brandless.css.js";
import { mollerBil } from "@gnist/themes/themes/mollerBil.css.js";
import { skoda } from "@gnist/themes/themes/skoda.css.js";
import { vw } from "@gnist/themes/themes/vw.css.js";
import { dahles } from "@gnist/themes/themes/dahles.css.js";
import { autoria } from "@gnist/themes/themes/autoria.css.js";
import { audi } from "@gnist/themes/themes/audi.css.js";
import { cupra } from "@gnist/themes/themes/cupra.css.js";
import { globalTextStyles } from "@gnist/themes/typography.css";
import "@gnist/design-system/fonts/moller";
import "@gnist/design-system/fonts/bilhold";
import "@gnist/design-system/fonts/skoda";
import "@gnist/design-system/fonts/gumpen";
import "@gnist/design-system/fonts/VW";
import "@gnist/design-system/fonts/dahles";
import "@gnist/design-system/fonts/autoria";
import "@gnist/design-system/fonts/audi";
import "@gnist/design-system/fonts/cupra";
import "@gnist/design-system/fonts/tools";
document.body.classList.add(bilholdLight);
globalTextStyles.forEach((c) => {
document.body.classList.add(c);
});
export const App: React.FC = () => {
return (
<LocalizationProvider language="en">
{/* ...the rest of your app here...*/}
</LocalizationProvider>
);
};
Next.js projects
If you are setting up in a Next.js project, the procedure is quite the same.
You will need to install and use @vanilla-extract/next-plugin
:
npm install -D @vanilla-extract/next-plugin
With this setup, your next.config.mjs
might look like this:
import { createVanillaExtractPlugin } from "@vanilla-extract/next-plugin";
const withVanillaExtract = createVanillaExtractPlugin();
const nextConfig = {};
export default withVanillaExtract(nextConfig);
If you are running a React version 18 project, you will also need to add this to your tsconfig.json
for it to work with this React 17 library.
"paths": {
...
"react": [ "./node_modules/@types/react"]
}
Then add the styling to your layout.tsx
file. It might look like this:
import { bilholdLight } from "@gnist/themes/themes/bilholdLight.css.js";
import { globalTextStyles } from "@gnist/themes/typography.css.js";
import "@gnist/design-system/fonts/bilhold";
const bodyClassList = [bilholdLight, ...globalTextStyles];
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={bodyClassList.join(" ")}>{children}</body>
</html>
);
}
Using components
Finally, import components from @gnist/design-system
:
import { PrimaryButton } from "@gnist/design-system";
export default function Home() {
return <PrimaryButton>Hello</PrimaryButton>;
}
Pages Router
If you are running Pages Router, add transpilePackages
to next.config.mjs
so that Vanilla Extract is applied to the library code:
const nextConfig = {
transpilePackages: ["@gnist/design-system", "@gnist/themes"],
};
As Pages Router does not have layout.tsx
, you need to split the setup between
pages/_document.tsx
and pages/_app.tsx
.
_document.tsx
runs once on the server. Use a named import here to get the theme class for :
import { bilholdLight } from "@gnist/themes/themes/bilholdLight.css.js";
import { globalTextStyles } from "@gnist/themes/typography.css.js";
import "@gnist/design-system/fonts/bilhold";
const bodyClassList = [bilholdLight, ...globalTextStyles];
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={bodyClassList.join(" ")}>{children}</body>
</html>
);
}
_app.tsx
runs on every route change. Here you must use side-effect imports for the same theme and typography so the CSS actually ends up in the client bundle:
import { LocalizationProvider } from "@gnist/design-system";
import "@gnist/design-system/fonts/bilhold";
import "@gnist/themes/themes/bilholdLight.css.js";
import "@gnist/themes/typography.css.js";
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<LocalizationProvider language="en">
<Component {...pageProps} />
</LocalizationProvider>
);
}
This ensures:
_document.tsx
sets the correct theme class on and .
_app.tsx
loads the theme’s CSS variables and typography tokens into the client bundle.
If you are migrating from the old component library @moller/design.system
, please see the migration guide.