react-dsfr
GitHubComponentsPlayground
  • πŸ”§Initial setup
  • πŸ”€Integration with routing libs
  • 🦺Class names type safety
  • 🎨Colors
  • 🧩Components
  • β˜‘οΈIcons
  • πŸ’…CSS in JS
  • 🌎Internationalization
  • πŸŒ…Importing assets
  • 🀝MUI integration
  • πŸ•ŠοΈCustom Branding
  • πŸ“–Storybook
  • πŸ“ŠAnalytics
  • πŸ”’Content-Security-Policy
  • πŸ“¦Publishing a NPM modules that depends on react-dsfr
  • πŸ’ŸContributing
Powered by GitBook
LogoLogo

Links

  • GitHub
  • Playground
  • Components

2022-2023 PΓ΄le logiciel libre d'Etalab - MIT license

On this page

Was this helpful?

Edit on GitHub
Export as PDF

Initial setup

Setup @codegouvfr/react-dsfr in your project or start from a template

NextIntegration with routing libs

Last updated 1 month ago

Was this helpful?

If you already had the DSFR installed in your project, let's start from scratch:

  • Remove from your dependencies.

  • Remove the import ofdsfr.css, dsfr.module.js the favicon and the fonts.

  • Remove the data-fr-scheme (and data-fr-theme ) attribude from your <html/> tag

yarn add @codegouvfr/react-dsfr
npm install --save @codegouvfr/react-dsfr
pnpm add @codegouvfr/react-dsfr

And add this file to the root of your project, to enable pre & post scripts with pnpm:

.npmrc
enable-pre-post-scripts=true

When we say Yarn we usually refer to Yarn 1.x as most dev teams (Including me) havent upgraded to the newest version (for good reasons).

If you want to use Yarn Berry you be aware that pre- post- scripts aren't supported.

So you must do something like "dev": "copy-dsfr-to-public && next dev" (same thing for start)

Also you must configure it so it uses node_modules (sorry)

If you want a more complete starter with a Ready yo use stack that includes routing, autentication, internationalisation ect. you can also use this starter instead:

Add these three scripts to your package.json:

package.json
"scripts": {
    "predev": "react-dsfr update-icons",
    "prebuild": "react-dsfr update-icons"
}

Trigger the execution of the postinstall script by running:

yarn # Or 'npm install' or 'pnpm install'

Add the following tags in the <head />

index.html
<link rel="apple-touch-icon" href="./node_modules/@codegouvfr/react-dsfr/favicon/apple-touch-icon.png" />
<link rel="icon" href="./node_modules/@codegouvfr/react-dsfr/favicon/favicon.svg" type="image/svg+xml" />
<link rel="shortcut icon" href="./node_modules/@codegouvfr/react-dsfr/favicon/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="./node_modules/@codegouvfr/react-dsfr/favicon/manifest.webmanifest" crossorigin="use-credentials" />

<link rel="stylesheet" href="./node_modules/@codegouvfr/react-dsfr/main.css" />
src/main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
startReactDsfr({ defaultColorScheme: "system" });

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

You're all set! Next step for you is to setup the integration with your routing library (react-router for example).

yarn add @codegouvfr/react-dsfr
yarn add --dev sass
npx degit https://github.com/garronej/react-dsfr-next-appdir-demo/src/dsfr-bootstrap src/dsfr-bootstrap
next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  webpack: config => {
    config.module.rules.push({
      test: /\.woff2$/,
      type: "asset/resource"
    });
    return config;
  }
};

export default nextConfig;
package.json
"scripts": {
    "predev": "react-dsfr update-icons",
    "prebuild": "react-dsfr update-icons"
}
src/app/layout.tsx
import { getHtmlAttributes, DsfrHead } from "../dsfr-bootstrap/server-only-index";
import { DsfrProvider } from "../dsfr-bootstrap";

export default function RootLayout({ children }: { children: React.JSX.Element; }) {
  const lang = undefined; // Can be "fr" or "en" ...
  return (
    <html {...getHtmlAttributes({ lang })} >
      <head>
        <DsfrHead />
      </head>
      <body>
        <DsfrProvider lang={lang}>
          {children}
        </DsfrProvider>
      </body>
    </html>
  );
}
src/app/page.tsx
import { StartDsfrOnHydration } from "../dsfr-bootstrap";

export default function Page() {
  return (
    <>
      {/* Important: You must mount this component on every pages of your App! */}
      <StartDsfrOnHydration />
      <h1>Welcome!</h1>
    </>
  );
}

You are in this case if you have a pages/ directory at the root of your project.

# If you plan to use MUI:  
yarn add @mui/material @emotion/react @emotion/server @emotion/styled @mui/material @emotion/react
next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  webpack: config => {
    config.module.rules.push({
      test: /\.woff2$/,
      type: "asset/resource"
    });
    return config;
  },
  //This option requires Next 13.1 or newer, if you can't update you can use this plugin instead: https://github.com/martpie/next-transpile-modules
  transpilePackages: [
      "@codegouvfr/react-dsfr", 
      "tss-react" // This is for MUI or if you use htts://tss-react.dev
  ],
  output: "export"
};

module.exports = nextConfig
package.json
"scripts": {
    "predev": "react-dsfr update-icons",
    "prebuild": "react-dsfr update-icons"
}
pages/_app.tsx
import type { AppProps } from "next/app";
import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir";
import Link from "next/link";

// Only in TypeScript projects
declare module "@codegouvfr/react-dsfr/next-pagesdir" {
    interface RegisterLink { 
        Link: typeof Link;
    }
}

const { 
    withDsfr,
    dsfrDocumentApi
} = createNextDsfrIntegrationApi({
    defaultColorScheme: "system",
    Link
});

export { dsfrDocumentApi };

function App({ Component, pageProps }: AppProps) {
    return <Component {...pageProps} />;
}

export default withDsfr(App);
pages/_document.tsx
import { Html, Head, Main, NextScript, DocumentProps } from "next/document";
import { dsfrDocumentApi } from "./_app";

const { 
  getColorSchemeHtmlAttributes, 
  augmentDocumentForDsfr 
} = dsfrDocumentApi;

export default function Document(props: DocumentProps) {
  return (
    <Html {...getColorSchemeHtmlAttributes(props)}>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

augmentDocumentForDsfr(Document);

The create-react-app project is no longer being maintained. If you are starting a new project you'll probably be beter off with Vite.

Add these three scripts to your package.json:

package.json
"scripts": {
    ...
    "postinstall": "react-dsfr copy-static-assets",
    "predev": "react-dsfr update-icons",
    "prebuild": "react-dsfr update-icons"
},
...
"jest": {
    "transformIgnorePatterns": [
      "node_modules/(?!@codegouvfr/react-dsfr)"
    ]
}

Trigger the execution of the postinstall script by running:

yarn # Or 'npm install' or 'pnpm install'

Add the following code in the <head />

public/index.html
<link rel="apple-touch-icon" href="%PUBLIC_URL%/dsfr/favicon/apple-touch-icon.png" />
<link rel="icon" href="%PUBLIC_URL%/dsfr/favicon/favicon.svg" type="image/svg+xml" />
<link rel="shortcut icon" href="%PUBLIC_URL%/dsfr/favicon/favicon.ico" type="image/x-icon" />
<link rel="manifest" href="%PUBLIC_URL%/dsfr/favicon/manifest.webmanifest" crossorigin="use-credentials" />

<link rel="stylesheet" href="%PUBLIC_URL%/dsfr/utility/icons/icons.min.css" />
<link rel="stylesheet" href="%PUBLIC_URL%/dsfr/dsfr.min.css" />
src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
startReactDsfr({ defaultColorScheme: "system" });

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

You're all set! Next step for you is to setup de integration with your routing library (react-router for example)

Avoiding or flash of unstyled text (FOUT)

You can avoid having a flash of unstyled text by preloading the font variant used on your homepage (look in the network tab of your browser dev tools what are the font downloaded initially).

Add the following tags in the <head />

index.html
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Light.woff2" as="font" crossorigin="anonymous" />-->
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Light_Italic.woff2" as="font" crossorigin="anonymous" />-->
<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Regular.woff2" as="font" crossorigin="anonymous" />
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Regular_Italic.woff2" as="font" crossorigin="anonymous" />-->
<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Medium.woff2" as="font" crossorigin="anonymous" />
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Medium_Italic.woff2" as="font" crossorigin="anonymous" />-->
<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Bold.woff2" as="font" crossorigin="anonymous" />
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Marianne-Bold_Italic.woff2" as="font" crossorigin="anonymous" />-->
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Spectral-Regular.woff2" as="font" crossorigin="anonymous" />-->
<!--<link rel="preload" href="./node_modules/@codegouvfr/react-dsfr/dsfr/fonts/Spectral-ExtraBold.woff2" as="font" crossorigin="anonymous" />-->
src/app/layout.tsx
import { getHtmlAttributes, DsfrHead } from "../dsfr-bootstrap/server-only-index";
import { DsfrProvider } from "../dsfr-bootstrap";

export default function RootLayout({ children }: { children: React.JSX.Element; }) {
  const lang = undefined; // Can be "fr" or "en" ...
  return (
    <html {...getHtmlAttributes({ lang })} >
      <head>
        <DsfrHead 
          preloadFonts={[
	    //"Marianne-Light",
            //"Marianne-Light_Italic",
	    "Marianne-Regular",
	    //"Marianne-Regular_Italic",
	    "Marianne-Medium",
	    //"Marianne-Medium_Italic",
	    "Marianne-Bold"
	    //"Marianne-Bold_Italic",
	    //"Spectral-Regular",
	    //"Spectral-ExtraBold"
	  ]}
        />
      </head>
      <body>
        <DsfrProvider lang={lang}>
          {children}
        </DsfrProvider>
      </body>
    </html>
  );
}
pages/_app.tsx
import type { AppProps } from "next/app";
import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir";
import Link from "next/link";

// Only in TypeScript projects
declare module "@codegouvfr/react-dsfr/next-pagesdir" {
    interface RegisterLink { 
        Link: typeof Link;
    }
}

const { 
    withDsfr,
    dsfrDocumentApi
} = createNextDsfrIntegrationApi({
    defaultColorScheme: "system",
    Link,
    preloadFonts: [
  	//"Marianne-Light",
        //"Marianne-Light_Italic",
	"Marianne-Regular",
	//"Marianne-Regular_Italic",
	"Marianne-Medium",
	//"Marianne-Medium_Italic",
	"Marianne-Bold",
	//"Marianne-Bold_Italic",
	//"Spectral-Regular",
	//"Spectral-ExtraBold"
    ]
});

export { dsfrDocumentApi };

function App({ Component, pageProps }: AppProps) {
    return <Component {...pageProps} />;
}

export default withDsfr(App);

Add the following code in the <head />

public/index.html
<%
[
  //"Marianne-Light",
  //"Marianne-Light_Italic",
  "Marianne-Regular",
  //"Marianne-Regular_Italic",
  "Marianne-Medium",
  //"Marianne-Medium_Italic",
  "Marianne-Bold",
  //"Marianne-Bold_Italic",
  //"Spectral-Regular",
  //"Spectral-ExtraBold"
].forEach(function(name){ %>
  <link rel="preload" href="%PUBLIC_URL%/dsfr/fonts/<%=name%>.woff2" as="font" crossorigin="anonymous" />
<% }); %>

Using Nx monorepo? See .

This documentation is for (aka the legacy next setup).

Your framework isn't supported? Let's ! Note: We don't have a custom integration for it but react-dsfr has been reported working with .

πŸ”§
this
πŸ”€Integration with routing libs
Next projects using the Page Router
πŸ”€Integration with routing libs
get in touch
Gatsby
@gouvfr/dsfr
GitHub - garronej/react-dsfr-vite-demoGitHub
Demo setup in production here:
https://react-dsfr-vite-demo.vercel.app/
GitHub - InseeFrLab/vite-insee-starter: A template project for SPAsGitHub
It's live here:
https://vite-insee-starter.demo-domain.ovh/
GitHub - garronej/react-dsfr-next-appdir-demo: πŸš€ Next Appdir + react-dsfr + MUI + TSSGitHub
Starter project in prod here:
https://react-dsfr-next-appdir-demo.vercel.app/
GitHub - garronej/react-dsfr-next-demo: Demo of no white flash when reloading in SSRGitHub
Starter project in prod here:
https://react-dsfr-next-demo.vercel.app/
GitHub - garronej/react-dsfr-cra-demo: Demo setup fro @codegouvfr/react-dsfr in a Create-react-app projectGitHub
See demo setup in production here:
https://react-dsfr-cra-demo.vercel.app/
Logo
Logo
Logo
Gatsby / Static Website Generator support ? Β· Issue #204 Β· codegouvfr/react-dsfrGitHub
Logo
Logo
Logo