๐งInitial setup
Setup @codegouvfr/react-dsfr in your project or start from a template
If you already had the DSFR installed in your project, let's start from scratch:
Remove
@gouvfr/dsfr
from your dependencies.Remove the import of
dsfr.css, dsfr.module.js the favicon and the fonts.
Remove
the data-fr-scheme
(anddata-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:
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:
Using Nx monorepo? See this.
Add these three scripts to your 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 />
<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" />
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).
๐Integration with routing libsThis documentation is for Next projects using the App router.
You are in this case if you have a app/
directory at the root of your project.
Despite the setup process not being as streamlined as one might hope due to certain Next specific limitations, the library is fully compatible with Next.js App Router (see demo). Most component featured in this toolkit are RSC ready, those that are not are labeled using the "use client"
directive.
You may experience white flashes in dev mode but not in production. ๐
yarn add --dev sass
# If you plan to use MUI:
yarn add @mui/material @emotion/react @emotion/server @emotion/styled @mui/material @emotion/react
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack: config => {
config.module.rules.push({
test: /\.woff2$/,
type: "asset/resource"
});
return config;
}
};
module.exports = nextConfig;
"scripts": {
"predev": "react-dsfr update-icons",
"prebuild": "react-dsfr update-icons"
}
import type { DefaultColorScheme } from "@codegouvfr/react-dsfr/next-appdir";
export const defaultColorScheme: DefaultColorScheme = "system";
"use client";
import { startReactDsfr } from "@codegouvfr/react-dsfr/next-appdir";
import { defaultColorScheme } from "./defaultColorScheme";
import Link from "next/link";
declare module "@codegouvfr/react-dsfr/next-appdir" {
interface RegisterLink {
Link: typeof Link;
}
}
startReactDsfr({ defaultColorScheme, Link });
export function StartDsfr(){
//Yes, leave null here.
return null;
}
import { DsfrHead } from "@codegouvfr/react-dsfr/next-appdir/DsfrHead";
import { DsfrProvider } from "@codegouvfr/react-dsfr/next-appdir/DsfrProvider";
import { getHtmlAttributes } from "@codegouvfr/react-dsfr/next-appdir/getHtmlAttributes";
import { StartDsfr } from "./StartDsfr";
import { defaultColorScheme } from "./defaultColorScheme";
import Link from "next/link";
export default function RootLayout({ children }: { children: JSX.Element; }) {
//NOTE: The lang parameter is optional and defaults to "fr"
const lang = "fr";
return (
<html {...getHtmlAttributes({ defaultColorScheme, lang })} >
<head>
<StartDsfr />
<DsfrHead Link={Link} />
</head>
<body>
<DsfrProvider lang={lang}>
{children}
</DsfrProvider>
</body>
</html>
);
}
Yes MUI v5 and v5 are supported in Next App Router. See instructions.
This documentation is for Next projects using the Page Router (aka the legacy next setup).
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
/** @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
"scripts": {
"predev": "react-dsfr update-icons",
"prebuild": "react-dsfr update-icons"
}
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);
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
:
"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 />
<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" />
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)
๐Integration with routing libsYour framework isn't supported? Let's get in touch! Note: We don't have a custom integration for it but react-dsfr has been reported working with Gatsby.
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 />
<!--<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" />-->
import { DsfrHead } from "@codegouvfr/react-dsfr/next-appdir/DsfrHead";
import { DsfrProvider } from "@codegouvfr/react-dsfr/next-appdir/DsfrProvider";
import { getHtmlAttributes } from "@codegouvfr/react-dsfr/next-appdir/getHtmlAttributes";
import StartDsfr from "./StartDsfr";
import { defaultColorScheme } from "./defaultColorScheme";
export default function RootLayout({ children }: { children: JSX.Element; }) {
return (
<html {...getHtmlAttributes({ defaultColorScheme })} >
<head>
<StartDsfr />
<DsfrHead
defaultColorScheme={defaultColorScheme}
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 defaultColorScheme={defaultColorScheme}>
{children}
</DsfrProvider>
</body>
</html>
);
}
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 />
<%
[
//"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" />
<% }); %>
Last updated