# Initial setup

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

{% embed url="<https://youtu.be/5q88JgXUAY4>" %}

{% hint style="warning" %}
If you already had the DSFR installed in your project, let's start from scratch:

* Remove [`@gouvfr/dsfr`](https://www.npmjs.com/package/@gouvfr/dsfr) from your dependencies.
* Remove the import of`dsfr.css, dsfr.module.js the favicon and the fonts.`
* Remove `the data-fr-scheme` (and `data-fr-theme` ) attribude from your `<html/>` tag
  {% endhint %}

{% tabs %}
{% tab title="yarn" %}

```bash
yarn add @codegouvfr/react-dsfr
```

{% endtab %}

{% tab title="npm" %}

```bash
npm install --save @codegouvfr/react-dsfr
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add @codegouvfr/react-dsfr
```

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

{% code title=".npmrc" %}

```properties
enable-pre-post-scripts=true
```

{% endcode %}
{% endtab %}

{% tab title="Yarn Berry (a.k.a Yarn 3 or Yarn modern)" %}
{% hint style="warning" %}
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).
{% endhint %}

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)
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="Vite" %}
{% embed url="<https://github.com/garronej/react-dsfr-vite-demo>" %}
Demo setup in production here: <https://react-dsfr-vite-demo.vercel.app/>
{% endembed %}

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:&#x20;

{% embed url="<https://github.com/InseeFrLab/vite-insee-starter>" %}
It's live here: <https://vite-insee-starter.demo-domain.ovh/>
{% endembed %}

{% hint style="info" %}
Using Nx monorepo? See [this](https://github.com/codegouvfr/react-dsfr/issues/328#issuecomment-2429157963).
{% endhint %}

Add these three scripts to your `package.json`:

<pre class="language-json" data-title="package.json"><code class="lang-json">"scripts": {
<strong>    "predev": "react-dsfr update-icons",
</strong><strong>    "prebuild": "react-dsfr update-icons"
</strong>}
</code></pre>

Trigger the execution of the postinstall script by running:

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

Add the following tags in the `<head />`

{% code title="index.html" %}

```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" />
```

{% endcode %}

<pre class="language-tsx" data-title="src/main.tsx"><code class="lang-tsx">import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
<strong>import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
</strong><strong>startReactDsfr({ defaultColorScheme: "system" });
</strong>
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  &#x3C;React.StrictMode>
    &#x3C;App />
  &#x3C;/React.StrictMode>
);
</code></pre>

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

{% content-ref url="/pages/87BiqajHbI0WtezSVwJM" %}
[Integration with routing libs](/routing)
{% endcontent-ref %}
{% endtab %}

{% tab title="Next.js App Router" %}
{% embed url="<https://github.com/garronej/react-dsfr-next-appdir-demo>" %}
Starter project in prod here: <https://react-dsfr-next-appdir-demo.vercel.app/>
{% endembed %}

```bash
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
```

<pre class="language-json" data-title="package.json"><code class="lang-json">"scripts": {
<strong>    "predev": "react-dsfr update-icons",
</strong><strong>    "prebuild": "react-dsfr update-icons"
</strong>}
</code></pre>

<pre class="language-tsx" data-title="src/app/layout.tsx"><code class="lang-tsx"><strong>import { getHtmlAttributes, DsfrHead } from "../dsfr-bootstrap/server-only-index";
</strong><strong>import { DsfrProvider } from "../dsfr-bootstrap";
</strong>
export default function RootLayout({ children }: { children: React.JSX.Element; }) {
  const lang = undefined; // Can be "fr" or "en" ...
  return (
<strong>    &#x3C;html {...getHtmlAttributes({ lang })} >
</strong>      &#x3C;head>
<strong>        &#x3C;DsfrHead />
</strong>      &#x3C;/head>
      &#x3C;body>
<strong>        &#x3C;DsfrProvider lang={lang}>
</strong>          {children}
<strong>        &#x3C;/DsfrProvider>
</strong>      &#x3C;/body>
    &#x3C;/html>
  );
}
</code></pre>

<pre class="language-tsx" data-title="src/app/page.tsx"><code class="lang-tsx"><strong>import { StartDsfrOnHydration } from "../dsfr-bootstrap";
</strong>
export default function Page() {
  return (
    &#x3C;>
      {/* Important: You must mount this component on every pages of your App! */}
<strong>      &#x3C;StartDsfrOnHydration />
</strong>      &#x3C;h1>Welcome!&#x3C;/h1>
    &#x3C;/>
  );
}
</code></pre>

{% endtab %}

{% tab title="Next.js Pages Router" %}
{% hint style="info" %}
This documentation is for [Next projects using the Page Router](https://nextjs.org/docs/pages/building-your-application/routing) (aka the legacy next setup).

You are in this case if you have a `pages/` directory at the root of your project.
{% endhint %}

{% embed url="<https://github.com/garronej/react-dsfr-next-demo>" %}
Starter project in prod here: <https://react-dsfr-next-demo.vercel.app/>
{% endembed %}

```bash
# If you plan to use MUI:  
yarn add @mui/material @emotion/react @emotion/server @emotion/styled @mui/material @emotion/react
```

<pre class="language-javascript" data-title="next.config.js"><code class="lang-javascript">/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
<strong>  //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
</strong><strong>  transpilePackages: [
</strong><strong>      "@codegouvfr/react-dsfr", 
</strong><strong>      "tss-react" // This is for MUI or if you use htts://tss-react.dev
</strong><strong>  ],
</strong>  output: "export"
};

module.exports = nextConfig
</code></pre>

<pre class="language-json" data-title="package.json"><code class="lang-json">"scripts": {
<strong>    "predev": "react-dsfr update-icons",
</strong><strong>    "prebuild": "react-dsfr update-icons"
</strong>}
</code></pre>

{% code title="pages/\_app.tsx" %}

```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);
```

{% endcode %}

{% code title="pages/\_document.tsx" %}

```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);
```

{% endcode %}
{% endtab %}

{% tab title="Create React App" %}
{% hint style="warning" %}
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.
{% endhint %}

{% embed url="<https://github.com/garronej/react-dsfr-cra-demo>" %}
See demo setup in production here: <https://react-dsfr-cra-demo.vercel.app/>
{% endembed %}

Add these three scripts to your `package.json`:

<pre class="language-json" data-title="package.json"><code class="lang-json">"scripts": {
    ...
    "postinstall": "react-dsfr copy-static-assets",
    "predev": "react-dsfr update-icons",
    "prebuild": "react-dsfr update-icons"
},
...
"jest": {
    "transformIgnorePatterns": [
<strong>      "node_modules/(?!@codegouvfr/react-dsfr)"
</strong>    ]
}
</code></pre>

Trigger the execution of the postinstall script by running:

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

Add the following code in the `<head />`

{% code title="public/index.html" %}

```ejs
<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" />
```

{% endcode %}

<pre class="language-tsx" data-title="src/index.tsx"><code class="lang-tsx">import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
<strong>import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
</strong><strong>startReactDsfr({ defaultColorScheme: "system" });
</strong>
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  &#x3C;React.StrictMode>
    &#x3C;App />
  &#x3C;/React.StrictMode>
);
</code></pre>

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

{% content-ref url="/pages/87BiqajHbI0WtezSVwJM" %}
[Integration with routing libs](/routing)
{% endcontent-ref %}
{% endtab %}

{% tab title="Other" %}
Your framework isn't supported? Let's [get in touch](https://github.com/codegouvfr/dsfr-react)!  \
\
Note: We don't have a custom integration for it but react-dsfr has been reported working with [Gatsby](https://www.gatsbyjs.com/).  <br>

{% embed url="<https://github.com/codegouvfr/react-dsfr/issues/204>" %}
{% endtab %}
{% endtabs %}

### 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).

{% tabs %}
{% tab title="Vite" %}
Add the following tags in the `<head />`

{% code title="index.html" %}

```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" />-->
```

{% endcode %}
{% endtab %}

{% tab title="Next.js App Router" %}

<pre class="language-tsx" data-title="src/app/layout.tsx"><code class="lang-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 (
    &#x3C;html {...getHtmlAttributes({ lang })} >
      &#x3C;head>
        &#x3C;DsfrHead 
<strong>          preloadFonts={[
</strong><strong>	    //"Marianne-Light",
</strong><strong>            //"Marianne-Light_Italic",
</strong><strong>	    "Marianne-Regular",
</strong><strong>	    //"Marianne-Regular_Italic",
</strong><strong>	    "Marianne-Medium",
</strong><strong>	    //"Marianne-Medium_Italic",
</strong><strong>	    "Marianne-Bold"
</strong><strong>	    //"Marianne-Bold_Italic",
</strong><strong>	    //"Spectral-Regular",
</strong><strong>	    //"Spectral-ExtraBold"
</strong><strong>	  ]}
</strong>        />
      &#x3C;/head>
      &#x3C;body>
        &#x3C;DsfrProvider lang={lang}>
          {children}
        &#x3C;/DsfrProvider>
      &#x3C;/body>
    &#x3C;/html>
  );
}
</code></pre>

{% endtab %}

{% tab title="Next.js Pages Router" %}

<pre class="language-tsx" data-title="pages/_app.tsx"><code class="lang-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,
<strong>    preloadFonts: [
</strong><strong>  	//"Marianne-Light",
</strong><strong>        //"Marianne-Light_Italic",
</strong><strong>	"Marianne-Regular",
</strong><strong>	//"Marianne-Regular_Italic",
</strong><strong>	"Marianne-Medium",
</strong><strong>	//"Marianne-Medium_Italic",
</strong><strong>	"Marianne-Bold",
</strong><strong>	//"Marianne-Bold_Italic",
</strong><strong>	//"Spectral-Regular",
</strong><strong>	//"Spectral-ExtraBold"
</strong><strong>    ]
</strong>});

export { dsfrDocumentApi };

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

export default withDsfr(App);
</code></pre>

{% endtab %}

{% tab title="Create React App" %}
Add the following code in the `<head />`

{% code title="public/index.html" %}

```ejs
<%
[
  //"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" />
<% }); %>
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Integration with routing libs

Like react-router or Next.js file system based route.

Depending on the framework or routing library you are using, links between pages are not handled the same way.

Usually, you'll have a `<Link />` component provided by your routing library of choice. You need to let `react-dsfr` know about it so that whenever a link is needed in a DSFR component, you can provide the correct props for your `<Link />` component.

When registering your Link component, its props type will propagate to the react-dsfr API.

{% tabs %}
{% tab title="Next.js App router" %}
Follow the setup described in the getting started section:

{% embed url="<https://react-dsfr.codegouv.studio/#tab-next.js-app-router>" %}

**Usage Examples**

Client side routing

```tsx
import { Card } from "@codegouvfr/react-dsfr/Card";

<Card
  linkProps={{
    to: "/my-page"
  }}
/>
```

The `<Link />` component from react-router will be used.

**External links:**

```tsx

linkProps={{
  href: "https://example.com"
  target="_blank"
}}
```

When react-dsfr detects that the `href` points to an external website it will use a regular `<a/>` instead of the `<Link />` component.

**Mailto links**

```tsx

linkProps={{
  href: "mailto:contact@code.gouv.fr"
}}
```

Same goes for the mailto links.

**Converting a link to a button**

```tsx
linkProps={{  
  href: "#"
  onClick: ()=> { /* ... */ }
}}
```

React-dsfr will automatically convert the underlying HTML element into a `<button />` that looks like a link for better Accessibility.
{% endtab %}

{% tab title="Next.js Pages router" %}
{% hint style="info" %}
This is how you are instructed to set it up by default (no change from the [Initial setup](https://react-dsfr.codegouv.studio/pages/sab22tVAGIAv0NFq3eXL#next.js) guide)
{% endhint %}

<pre class="language-tsx" data-title="pages/_app.tsx"><code class="lang-tsx">import type { AppProps } from "next/app";
import { fr } from "@codegouvfr/react-dsfr";
import { createNextDsfrIntegrationApi } from "@codegouvfr/react-dsfr/next-pagesdir";
<strong>import Link from "next/link";
</strong>
<strong>// Only in TypeScript projects
</strong><strong>declare module "@codegouvfr/react-dsfr/next-pagesdir" {
</strong><strong>    interface RegisterLink { 
</strong><strong>        Link: typeof Link;
</strong><strong>    }
</strong><strong>}
</strong>
const { 
    withDsfr,
    dsfrDocumentApi
} = createNextDsfrIntegrationApi({
    defaultColorScheme: "system",
<strong>    Link
</strong>});

export { dsfrDocumentApi };

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

export default withDsfr(App);
</code></pre>

Example [here](https://github.com/codegouvfr/react-dsfr/blob/main/test/integration/next-pagesdir/pages/_app.tsx).

**Examples**

Client side routing

```tsx
import { Card } from "@codegouvfr/react-dsfr/Card";

<Card
  linkProps={{
    href: "/my-page"
  }}
/>
```

The `<Link />` component from react-router will be used.

**External links:**

```tsx

linkProps={{
  href: "https://example.com"
  target="_blank"
}}
```

When react-dsfr detects that the `href` points to an external website it will use a regular `<a/>` instead of the `<Link />` component.

**Mailto links**

```tsx

linkProps={{
  to: "mailto:contact@code.gouv.fr"
}}
```

Same goes for the mailto links.

**Converting a link to a button**

```tsx
linkProps={{  
  to: "#"
  onClick: ()=> { /* ... */ }
}}
```

React-dsfr will automatically convert the underlying HTML element into a `<button />` that looks like a link for better Accessibility.
{% endtab %}

{% tab title="Tanstack" %}
Due to the fact that [@tanstack/react-router](https://tanstack.com/router/v1) is also implementing module augmentation it's just a tiny bit less straight forward to set up but it works great!

<pre class="language-tsx"><code class="lang-tsx">import React from "react";
import ReactDOM from "react-dom/client";
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
<strong>import { Link, type LinkProps } from "@tanstack/react-router";
</strong>
startReactDsfr({ 
    defaultColorScheme: "system", 
<strong>    Link 
</strong>});

<strong>declare module '@codegouvfr/react-dsfr/spa' {
</strong><strong>  interface RegisterLink {
</strong><strong>    Link: (props: LinkProps) => JSX.Element
</strong><strong>  }
</strong><strong>}
</strong>
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
    &#x3C;React.StrictMode>
            {/* ... */}
    &#x3C;/React.StrictMode>
);
</code></pre>

After that you will have type safety on the `linkProps`, you can use the to property as you would on the react router's `<Link />` component!  \
Note that if you want to link to external website (or use `mailto:`) you can use the href property instead of the to property (see below). &#x20;

<figure><img src="/files/Rk4U4r5T9t3NHpllL8Ak" alt=""><figcaption></figcaption></figure>

If you have a link that is a `mailto:` or a link to an external page, use the `href` property instead of `to`.  Example: &#x20;

<pre class="language-tsx"><code class="lang-tsx">&#x3C;Header
    navigation={[
        {
            text: "Contact",
            linkProps: {
<strong>                href: "mailto:support@data.gouv.fr"
</strong>            }
        },
        {
            text: "Écrire au président"
            linkProps: {
<strong>                href: "https://www.elysee.fr/ecrire-au-president-de-la-republique/"
</strong>            }
        }
    ]}
/>
</code></pre>

{% endtab %}

{% tab title="type-route" %}
[type-route](https://type-route.zilch.dev/) unlike most routing library doesn't export a `<Link />` component, `<a />` are used directly.

In consequence there isn't anything to setup.

**Examples**

Client side routing

```tsx
import { Card } from "@codegouvfr/react-dsfr/Card";
import { routes } from "...";

<Card
  linkProps={routes.myPage().link}
/>
```

Example [here](https://github.com/codegouvfr/react-dsfr/blob/e8b78dd5ad069a322fbcc34b34b25d4ac8214e34/test/integration/cra/src/index.tsx#L33).
{% endtab %}

{% tab title="react-router" %}
{% hint style="warning" %}
If you are starting a new project you might want to use  [TanStack Router](#tanstack) in place of  [react-router](https://reactrouter.com/en/main) as it is, at least in my opignion a much better routing library. &#x20;
{% endhint %}

<pre class="language-tsx"><code class="lang-tsx">import React from "react";
import ReactDOM from "react-dom/client";
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
<strong>import { Link } from "react-router-dom";
</strong>startReactDsfr({ 
    defaultColorScheme: "system", 
<strong>    Link 
</strong>});

<strong>//Only in TypeScript projects
</strong><strong>declare module "@codegouvfr/react-dsfr/spa" {
</strong><strong>    interface RegisterLink { 
</strong><strong>        Link: typeof Link;
</strong><strong>    }
</strong><strong>}
</strong>
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
    &#x3C;React.StrictMode>
            {/* ... */}
    &#x3C;/React.StrictMode>
);
</code></pre>

Everywhere a DSFR component accepts a `xxxLinkProps` you are expected to provide an object with a `to` property because `react-router`'s`<Link />` component expects a `to` prop instead of the typical href.\
\
You can find an example [here](https://github.com/codegouvfr/react-dsfr/blob/main/test/integration/vite/src/main.tsx).

**Examples**

Client side routing

```tsx
import { Card } from "@codegouvfr/react-dsfr/Card";

<Card
  linkProps={{
    to: "/my-page"
  }}
/>
```

The `<Link />` component from react-router will be used.

**External links:**

```tsx

linkProps={{
  to: "https://example.com"
  target="_blank"
}}
```

When react-dsfr detects that the `to` points to an external website it will use a regular `<a/>` Instead of the `<Link />` component.

**Mailto links**

```tsx
linkProps={{
  to: "mailto:contact@code.gouv.fr"
}}
```

Same goes for the mailto links.

**Converting a link to a button**

```tsx
linkProps={{  
  to: "#"
  onClick: ()=> { /* ... */ }
}}
```

React-dsfr will automatically convert the underlying HTML element into a `<button />` that looks like a link for better Accessibility.
{% endtab %}

{% tab title="Other" %}
You should be able to infer what needs to be done refering to the `react-router` instructions.

If the library you are using doesn't export a `<Link />` (like `type-route` for example) component, there isn't anything to do.
{% endtab %}
{% endtabs %}

####


# Class names type safety

It's like [clsx](https://www.npmjs.com/package/clsx) but you can only pass it classes that are from the dsfr.

<figure><img src="/files/NzVU6UyzijGQq43hm1tb" alt=""><figcaption></figcaption></figure>

You can't apply your custom classes using fr.cx(), you'll get type error, but you can combine a regular `cx()` or `clsx()` function and `fr.cx()`. Example:

```tsx
import { useStyles } from "tss-react/dsfr";
import { fr } from "@codegouvfr/react-dsfr";  

type Params = {
    className?: string;
};

export function MyComponent(params: Params){

   const { className } = params;  
   
   const { cx } = useStyles();
   
   return (
       <div className={cx(fr.cx("fr-p-10v"), className)}>
           //...
       </div>
   );

}
```


# Colors

Most of the time, when using the provided components from the Design System for French Republic (DSFR), there is no need to explicitly manipulate colors. These components are designed with a set of default colors that aim to maintain consistency and harmony across your application or website. However, when you are crafting a new component or customizing existing ones, it becomes essential to select the appropriate color scheme that aligns with the DSFR guidelines for your specific use case.

To assist you in effortlessly navigating through the DSFR color palette and selecting the perfect hues for your components, we provide you with a user-friendly color picker tool. This tool is designed to simplify the process of choosing colors that adhere to the DSFR’s design principles, ensuring that your custom components not only look visually appealing but also maintain a cohesive and unified design language.

{% embed url="<https://components.react-dsfr.codegouv.studio/?path=/docs/%F0%9F%8E%A8-color-helper--page>" %}
Color picker tool
{% endembed %}

{% embed url="<https://youtu.be/DAcioU4Q1kM>" %}
Tutorial
{% endembed %}


# Components

The components are documented individually on a separate website.

{% embed url="<https://components.react-dsfr.codegouv.studio/>" %}

### Customization

What to do if you want to customize the components beyond what the props allow.

#### The `classes` property

Every component of react-dsfr accepts an optional `classes` property that enables you to customize their look at a fine grained level.

<figure><img src="/files/1d70eadOBn4R9ej6FsT9" alt=""><figcaption><p>Available classes on the Alert components</p></figcaption></figure>

<figure><img src="/files/bSCH9l1mLGBxS4ukjkOZ" alt=""><figcaption><p>We add a 5v margin-top to the close button</p></figcaption></figure>

<figure><img src="/files/qlNoEZYtg2XXR3ZDTaKr" alt=""><figcaption><p>Before</p></figcaption></figure>

<figure><img src="/files/iu20eucc47wUNMQ6yrXI" alt=""><figcaption><p>After</p></figcaption></figure>

### Creating a custom component

{% embed url="<https://youtu.be/9uaPv-Q9fe4>" %}
Cusomizing a component - NOTE: theme.decisions... is now fr.colors.decisions...
{% endembed %}


# Icons

{% embed url="<https://youtu.be/FdabjOlaCUQ>" %}

Icons just work, you can copy paste any code from [the dsfr documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/fondamentaux-techniques/icone) and expect things to work.

{% hint style="info" %}
Whenever you add a new icon to your project, restart your local server. This will launch the `npx react-dsfr update-icons` script configured in the [Initial setup](/) (else you'll see a blue square instead of your icon).
{% endhint %}

```jsx
import { fr } from "@codegouvfr/react-dsfr";
import { Button } from "@codegouvfr/react-dsfr/Button";

<>
  <Button iconId="fr-icon-checkbox-circle-line">Label button MD</Button>
  <span className={fr.cx("fr-icon-ancient-gate-fill")} aria-hidden={true}/>
  <i className={fr.cx("fr-icon-ancient-gate-fill")} />
<>
```

<figure><img src="/files/OPnLd49o3BQQHvEa19zy" alt=""><figcaption></figcaption></figure>

But on top of that, all icons from [Remixicon](https://remixicon.com/) are supported.

You can go and search for a keyword:

<figure><img src="/files/mNCCbpVgZZIIwTAf0xTw" alt=""><figcaption><p>Searching for "download" on remixicon.com</p></figcaption></figure>

When you find something fitting, you can copy paste the class name ( starting with `ri-` ) and use it anywhere you would have used a `.fr-icon-xxxx` ! 🚀

Example:

```jsx
import { fr } from "@codegrouvfr/react-dsfr";
import { Button } from "@codegouvfr/react-dsfr/Button";

<>
  <Button iconId="ri-mail-download-line">Label button MD</Button>
  <span className={fr.cx("ri-mail-download-line")} aria-hidden={true}/>
  <i className={fr.cx("ri-mail-download-line")} />
<>
```

<figure><img src="/files/nVylkR2Dh52AdUFDoLfd" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
No need to worry about importing the correct icons file.

It's done automatically for you when you. &#x20;
{% endhint %}

The `fr.cx()` utility is also handy for autocompleting the icons that are supported:

<figure><img src="/files/0wq2o5Xu72zklXns4IZs" alt=""><figcaption><p>Using fr.cx()</p></figcaption></figure>


# CSS in JS

Compatibility with solutions like styled-components, emotion and TSS.

At build time `react-dsfr` parses the official [dsfr.css](https://unpkg.com/browse/@gouvfr/dsfr/dist/dsfr/dsfr.css) files and spits out a typed JavaScript representation of the DSFR. In particular, its [colors options](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/colorOptions.ts) and [decisions](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/getColorDecisions.ts), the [spacing system](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/spacing.ts) and the [breakpoints values](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/breakpoints.ts).

This enables to write DSFR compliant CSS in JS code, since we are able to expose function that are the equivalent of the DSFR utility classes.

{% hint style="success" %}
Checkout [the color selection tool](https://components.react-dsfr.codegouv.studio/?path=/docs/%F0%9F%8E%A8-color-helper--page).
{% endhint %}

{% tabs %}
{% tab title="Native" %}
You can use the style props on native react components but you won't be able to use the `fr.breakpoint` utility that enable to write responsive code.

<pre class="language-tsx"><code class="lang-tsx"><strong>import { fr } from "@codegouvfr/react-dsfr";
</strong>
export type Props = {
    className?: string;
};

export const MyComponent =(props: Props) => {

    const { className } = props;
    
    return (
	&#x3C;div 
	    className={className}
<strong>	    style={{
</strong><strong>	        padding: fr.spacing("10v"),
</strong><strong>		//SEE: https://components.react-dsfr.codegouv.studio/?path=/docs/%F0%9F%8E%A8-color-helper--page
</strong><strong>	        backgroundColor: fr.colors.decisions.background.alt.blueFrance.active
</strong><strong>	    }}
</strong>	>
	    &#x3C;span 
<strong>	        className={fr.cx("fr-p-1v")}
</strong>	        style={{
<strong>	            ...fr.spacing("margin", { "topBottom": "3v" })
</strong>	        }}
	    >
	        Hello World
	    &#x3C;/span>
	&#x3C;/div>
    );

};

</code></pre>

{% endtab %}

{% tab title="TSS (recommended)" %}
**tss-react**

{% embed url="<https://tss-react.dev>" %}
Dynamic CSS-in-TS syle engine
{% endembed %}

```bash
# Dependencies to install even if never used directly:
yarn add tss-react @emotion/react
```

```tsx
import { useState } from "react";
import { tss } from "tss-react";
//NOTE: If you get "SyntaxError: Cannot use import statement outside a module" add tss-react here in your next.config.js: https://github.com/garronej/react-dsfr-next-demo/blob/43ecfa03d5416f2446b6867af65c7e3c7e7e41ef/next.config.js#L14

export type Props = {
    className?: string;
};

export const MyComponent = (props: Props) => {
    const { className } = props;

    const [counter, setCounter] = useState(0);

    const { classes, cx } = useStyles({
        isClicked: couter > 0
    });

    return (
        <div className={cx(classes.root, className)} onClick={() => setCounter(counter + 1)}>
            <span className={cx(fr.cx("fr-p-1v"), classes.innerText)}>Hello World</span>
        </div>
    );
};

MyComponent.displayName = MyComponent.name;

const useStyles = tss
    .withName(MyComponent.name)
    .withParams<{ isClicked: boolean }>()
    .create(({ isClicked }) => ({
        root: {
            padding: fr.spacing("10v"),
            //SEE: https://components.react-dsfr.codegouv.studio/?path=/docs/%F0%9F%8E%A8-color-helper--page
            backgroundColor: fr.colors.decisions.background.active.redMarianne.default,
            "&:hover": {
                //Rules that apply when the mouse is hover
                backgroundColor: fr.colors.decisions.background.active.redMarianne.hover
            },
            [fr.breakpoints.up("md")]: {
                //Rules that applies only when the screen is md or up
            },
            border: !isClicked
                ? undefined
                : `1px solid ${fr.colors.decisions.border.active.blueFrance.default}`
        },
        innerText: {
            ...fr.spacing("margin", { topBottom: "3v" })
        }
    }));

```

You can also use TSS to apply global styles:

```tsx
import { GlobalStyles } from "tss-react";
import { fr } from "@codegouvfr/react-dsfr";

function App(){

    return (
        <>
            <GlobalStyles
                styles={{
                    html: {
                        overflowY: "scroll"
                    },
                    body: {
                        margin: 0,
                        borderWidth: 20,
                        borderStyle: "solid",
                        borderColor: fr.colors.decisions.border.actionHigh.success.default
                    }
                }}
            />
            {/*...rest of the app...*/}
        </>
    );

}
```

{% hint style="info" %}
Advantages of tss-react over other CSS in JS solutions

* I'm the author of TSS, it gets premium integration and support.
* I made tss-react in coordination the MUI team. (TSS is documented in the MUI documentation [here](https://mui.com/material-ui/migration/migrating-from-jss/#2-use-tss-react) and [here](https://mui.com/material-ui/guides/interoperability/#jss-tss)) so it works very well with it. Besides, getting MUI to correctly SSR in a Next.js setup is complicated ([see the reference repo](https://github.com/mui/material-ui/tree/HEAD/examples/nextjs-with-typescript)). With the help of TSS, [it's much easier](https://docs.tss-react.dev/ssr/next.js#single-emotion-cache).
  {% endhint %}
  {% endtab %}

{% tab title="styled" %}
{% embed url="<https://styled-components.com/>" %}

{% hint style="info" %}
[styled-component](https://styled-components.com/) and [@emotion/styled](https://emotion.sh/docs/styled) are equivalent API-wise so I give the example with Emotion since it has a better MUI integration.
{% endhint %}

```tsx
import styled from '@emotion/styled'
import { fr } from "@codegouvfr/react-dsfr";

export type Props = {
    className?: string;
};

export function MyComponentNotStyled(props: Props){

    const { className } = props;

    return (
	<div className={className}>
	    <span className={fr.cx("fr-p-1v")}>
	      Hello World
	    </span>
	</div>
    );

}

export const MyComponent = MyComponentNotStyled`
  padding: ${fr.spacing("10v")};
  background-color: ${fr.colors.decisions.background.alt.blueFrance.active};
  ${fr.breakpoints.up("md")}: {
    background-color: ${fr.colors.decisions.background.alt.beigeGrisGalet.active};
  }
  & > span {
    margin-top: ${fr.spacing("3v")};
    margin-bottom: ${fr.spacing("3v")};
  }
`;
```

Optionally, if you want to have access to `isDark` in your styles, but this is not nessesary because fr.colors uses CSS variables by default.

```tsx
import { ThemeProvider } from '@emotion/react'
import { useIsDark } from "@codegouvfr/react-dsfr/useIsDark";

function Root(){

    const { isDark } = useIsDark();

    return (
        <ThemeProvider theme={{ isDark }}>
            <App />
        </ThemeProvider>
    );

}

// Then you'll be able to do the following to have the 
// hex values of the colors instead of var(--xxx).

export const MyComponent = MyComponentNotStyled`
  background-color: ${({ theme: { isDark } })=> fr.colors.getHex({ isDark }).decisions.background.alt.blueFrance.active};
`;
```

{% endtab %}
{% endtabs %}

### spacing

For ensuring the spacing between elements is consistent throughout the website.

{% hint style="info" %}
This tool is build using [this file](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/spacing.ts) that is automatically generated from [dsfr.css](https://unpkg.com/browse/@gouvfr/dsfr/dist/dsfr/dsfr.css)
{% endhint %}

<pre class="language-tsx"><code class="lang-tsx"><strong>import { fr } from "@codegouvfr/react-dsfr";
</strong>
function MyComponent() {

    return (
        &#x3C;div 
            style={{ 
                marginTop: fr.spacing("2v"),
                ...fr.spacing("padding", { topBottom: "5w", left: 5 })
            }}
        />
    );

}
</code></pre>

The above code is equivalent to:

```tsx
import { fr } from "@codegouvfr/react-dsfr";

function MyComponent() {

    return (
        <div 
            style={{ 
                marginTop: fr.spacing("2v"),
                paddingTop: fr.spacing("5w"),
                paddingBottom: fr.spacing("5w"),
                paddingLeft: 5
            }}
        />
    );

}
```

Which is in turn equivalent to:

```tsx
import { fr } from "@codegouvfr/react-dsfr";

function MyComponent() {

    return (
        <div 
            style={{ 
                marginTop: "0.5rem",
                paddingTop: "2.5rem",
                paddingBottom: "2.5rem",
                paddingLeft: 5
            }}
        />
    );

}
```

<figure><img src="/files/5pH1Eh6vb22Ooulqy0Zh" alt=""><figcaption><p>You can read the returned value in em just by hovering the spacing function call</p></figcaption></figure>

### breakpoints

For writing responsive UIs with media query (`@media`).

{% hint style="info" %}
This tool is build using [this file](https://unpkg.com/browse/@codegouvfr/react-dsfr/src/fr/generatedFromCss/breakpoints.ts) that is automatically generated from [dsfr.css](https://unpkg.com/browse/@gouvfr/dsfr/dist/dsfr/dsfr.css)
{% endhint %}

```tsx
import { useStyles } from "tss-react";
import { fr } from "@codegouvfr/react-dsfr";

function MyComponent() {

    const { css, theme } = useStyles();
    
    return (
        <div
            className={css({
                width: "100px",
                height: "100px"
                backgroundColor: theme.decisions.background.flat.info.default,
                // On screen larger than MD the background color 
                // will be colors.decisions.background.alt.blueFrance.default.
                [fr.breakpoints.up("md")]: {
                    backgroundColor: theme.decisions.background.alt.blueFrance.default
                },
                maxWidth: fr.breakpoints.values.xl
            })}
        />
    );

}
```

<figure><img src="/files/INaXjwSyaubm39b2d1n0" alt=""><figcaption><p>This tool generates @media query for you that matches the DSFR breakpoints</p></figcaption></figure>

### colors

Using the `theme` object that holds the colors decisions and options.

{% hint style="success" %}
📣📣📣📣📣📣\
There is [a tool](https://components.react-dsfr.codegouv.studio/?path=/docs/%F0%9F%8E%A8-color-helper--page) at your disposal to help you pick your colors.\
Use it! It's great!\
📣📣📣📣📣📣📣
{% endhint %}

#### Using CSS variables (recommended)

This approad is React agnostic and yield the best performances. &#x20;

<pre class="language-typescript"><code class="lang-typescript"><strong>import { fr } from "@codegouvfr/react-dsfr";
</strong>
function MyComponent(){

  return (
    &#x3C;div style={{
      // The recommended method, using CSS variables: 
<strong>      backgroundColor: fr.colors.decisions.background.default.grey.default 
</strong>      // This is: backgroundColor: "var(--background-default-grey)"
    }} />
  );

}
</code></pre>

#### Using HEX color code

Some third party libraries might require you to provide explicit value as colors. &#x20;

When CSS variable references doesn't work you can do: &#x20;

<pre class="language-tsx"><code class="lang-tsx"><strong>import { fr } from "@codegouvfr/react-dsfr";
</strong><strong>import { useIsDark } from "@codegouvfr/react-dsfr/useIsDark";
</strong>
function MyComponent(){

<strong>  const { isDark } = useIsDark();
</strong>
  return (
    &#x3C;div style={{
<strong>      backgroundColor: fr.colors.getHex({ isDark }).decisionsbackground.default.grey.default
</strong>      // This is backgroundColor: "#161616" when isDark is true
      // and     backgroundColor: "#ffffff" when isDark is false
    }} />
  );

}
</code></pre>

### useIsDark()

You can access the active mode (isDark: true/false) in the `theme` object. However, if you want to manually switch the mode, you can use `setIsDark(true/false)` .

{% hint style="info" %}
Consider using the [\<Display />](https://components.react-dsfr.codegouv.studio/?path=/docs/components-display--default) component instead of trying to manually manage the active mode.
{% endhint %}

```tsx
import { 
   useIsDark, 
   getIsDark // Let you access the current value of isDark outside of React (client side only)
} from "@codegouvfr/react-dsfr/useIsDark";

function MyComponent(){

    const { isDark, setIsDark } = useIsDark();
    
    //isDark is a boolean that is true if the App is currently in dark mode.

    //Calling setIsDark(true) will switch the app in dark mode.
    //calling setIsDark("system") will set to whatever mode is signaled as prefered
    //by the user browser


}
```

If you want to use the isDark value in your styles: &#x20;

<pre class="language-tsx"><code class="lang-tsx">import { tss } from "tss-react";
import { useIsDark } from "@codegouvfr/react-dsfr/useIsDark";

function MyComponent(props){

    const { className } = props;
    
    const { isDark } = useIsDark();
    const { classes, cx } = useStyles({ isDark });
    
    return (
        &#x3C;div classNames={cx(classes.root, className)}>
           // ...
        &#x3C;/div>
    );
    
}

const useStyles = tss
<strong>  .withParams&#x3C;{ isDark: boolean; }>()
</strong><strong>  .create(({ isDark })=> ({
</strong>    root: { /* ... */ }
  }));
</code></pre>

### useBreakpointsValuesPx()

It returns the values in pixel of the different breakpoint ("xs", "md", "lg", "xl") based on the current root font size.

It can be used to do stuffs like this, geting the number of column of a responsive layout in JavaScript:

```tsx
import { useBreakpointsValuesPx } from "@codegouvfr/react-dsfr/useBreakpointsValuesPx";
import { useWindowInnerSize } from "@codegouvfr/react-dsfr/tools/useWindowInnerSize";

function useColumnCount(){

        const { breakpointsValues } = useBreakpointsValuesPx();

        const { windowInnerWidth } = useWindowInnerSize();

        const columnCount = (() => {
            if (windowInnerWidth < breakpointsValues.md) {
                return 1;
            }

            if (windowInnerWidth < breakpointsValues.xl) {
                return 2;
            }

            return 3;
        })();
        
        return collumnCount;

}
```

{% hint style="warning" %}
Be carefull though, favor using `fr.breakpoints` over client size mesurement and computation.

On the backend you can't know ahead of time the size of the screen of your users so this kind of approach will result in a flickering in SSR setups.

For example, your backend has no clue the size of the device making the request so it renders for a 1080p screen but the device making the request was, in fact, an iPhone and the first print is fully broken, the app becomes usable only after hydration.

Long story short, use this only if you are building an SPA.
{% endhint %}


# Internationalization

DSFR components contain hard coded strings.

These strings can be switched from a langage to another with a provider.

![When lang="en"](https://user-images.githubusercontent.com/6702424/202221151-9e04dd77-da52-4ce7-b1b1-5bb653addf50.png) ![When lang="fr"](https://user-images.githubusercontent.com/6702424/202221309-b11b89a7-4893-442b-ab2a-92f85177ba69.png)

Integration with i18n libraries

{% tabs %}
{% tab title="i18nifty" %}
{% embed url="<https://i18nifty.dev>" %}
A type safe internationalisation library for SPAs and Next.js
{% endembed %}

```tsx
import { useLang } from "i18n";

startDsfrReact({ 
  defaultColorScheme: "system",
  useLang: function useLangDsfr() {
        const { lang } = useLang();
        return lang;
  }
});
```

Example setup [in Next.js](https://github.com/etalab/etalab-website/blob/b427049dd9609ddbdd5fc2b42484d700e20851f4/pages/_app.tsx#L39-L42) / In a SPA.

{% hint style="warning" %}
DISCLAMER: I'm the author of i18nifty.

While I can confidently recommend it for SPAs, I have to warn you that using i18nifty in Next.js will force you to opt out from[ Automatic Static Optimization](https://nextjs.org/docs/messages/opt-out-auto-static-optimization) and bundle all your translations in the JavaScript bundle. SSR, SSO will work fine though.
{% endhint %}
{% endtab %}

{% tab title="Next.js i18n App Router" %}
{% embed url="<https://nextjs.org/docs/app/building-your-application/routing/internationalization>" %}
At the bottom you have setup examples
{% endembed %}

Assuming you have configured Next so that you have a lang prop provided to you in the main layout:

<pre class="language-tsx" data-title="app/[lang]/layout.txs"><code class="lang-tsx"><strong>import { i18n } from '../../i18n-config'
</strong>
<strong>export async function generateStaticParams() {
</strong><strong>  	return i18n.locales.map((locale) => ({ lang: locale }))
</strong><strong>}
</strong>
export default function Root({
  children,
  params,
}: {
  children: React.ReactNode
<strong>  params: { lang: string }
</strong>}) {
<strong>	const { lang } = params;
</strong>	return (
		&#x3C;html
<strong>			{...getHtmlAttributes({ defaultColorScheme, lang })}
</strong>		>
			&#x3C;head>
			{/*...*/}
			&#x3C;/head>
			&#x3C;body>
<strong>				&#x3C;DsfrProvider lang={lang}>
</strong>					{/*...*/}
				&#x3C;/DsfrProvider>
			&#x3C;/body>
		&#x3C;/html>
	);
}
</code></pre>

{% endtab %}

{% tab title="Next.js i18n Page Router" %}
{% embed url="<https://nextjs.org/docs/advanced-features/i18n-routing>" %}

Assuming you have enabled internationalized routing:

<pre class="language-tsx" data-title="pages/_app.tsx"><code class="lang-tsx">import { useRouter } from "next/router";

const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({
	"defaultColorScheme": "system",
	Link,
<strong>	useLang: () => {
</strong><strong>		const { locale = "fr" } = useRouter();
</strong><strong>		return locale;
</strong><strong>	}
</strong>});
</code></pre>

{% endtab %}

{% tab title="Other i18n library" %}
It's up to you to replace in the following example `"fr"` by the desired locale using to tooling exposed by your i18n library.

```tsx
startDsfrReact({ 
  defaultColorScheme: "system",
  useLang: () => "fr"
});
```

{% endtab %}
{% endtabs %}

### Adding translations or overwriting default text

The components usually come with one or two translations by default, typically english (`en`), spanish (`es`) and sometime german (`de`). [Illustration with the \<DarkModeSwitch /> component](https://github.com/codegouvfr/react-dsfr/blob/e8b78dd5ad069a322fbcc34b34b25d4ac8214e34/src/DarkModeSwitch.tsx#L162-L199).

You can add translation for extra language on a component basis, like so:

```tsx
import { addAlertTranslations } from "@codegouvfr/react-dsfr/Alert";

addAlertTranslations({
    lang: "zh-CN",
    messages: {
        hide message: "隐藏消息"
    }
});
```

The above code adds chinese (`zh-CN`) support for the Alert component. You can call `addAlertTranslations()` wherever, just be sure it's evaluated before the first use of the component, here `<Alert />`.

You can also use this approach for overwiting the default text. Example:

```tsx
import { addDisplayTranslations } from "@codegouvfr/react-dsfr/Display";

addDisplayTranslations({
	lang: "fr",
	messages: {
		"dark theme": "Thème sombre 🤩",
	}
});
```

<figure><img src="/files/Suxkt18nsr3IOaVZNVdP" alt="" width="188"><figcaption><p>It goes without saying this is not a recommended customization of the Display Modal</p></figcaption></figure>

#### With Next App Router

When utilizing Next in App Router mode, it's crucial to accurately add or overwrite translations at the proper location.

For components that you use as server components, such as `<Header />`, `<Footer />`, or the `<Display />` modal, you should make calls to `addXxxTranslation` within `app/layout.tsx`.

For components used as client components, and those explicitly marked as client components like [`<Alert />`](https://github.com/codegouvfr/react-dsfr/blob/5d912eb7295e03d010a148c46798909e53ba9261/src/Alert.tsx#L1) or [`<Tabs />`](https://github.com/codegouvfr/react-dsfr/blob/main/src/Tabs.tsx#L1), `addXxxTranslation` should be conducted in `app/StartDsfr.tsx`.


# Importing assets

How to import images, SVGs and other static DSFR resources

Let's say, [in the DSFR documentation](https://www.systeme-de-design.gouv.fr/elements-d-interface/composants/parametres-d-affichage), you come across the following HTML code.

```html
<!-- Official documentation code, don't copy paste that -->
<svg>
    <use xlink:href="../../../dist/artwork/dark.svg#artwork-minor" />
</svg>
```

Let's see how we would translate this into React.

{% tabs %}
{% tab title="Create React App / Vite / Others" %}
Most JS bundlers, by default, emits a separate file and exports the URL when comming across an import of a image or video file format.

```tsx
import artworkDarkSvgUrl from "@codegouvfr/react-dsfr/dsfr/artwork/dark.svg";

<svg>
    <use xlinkHref={`${artworkDarkSvgUrl}#artwork-minor`} />
</svg>
```

{% endtab %}

{% tab title="Next.js" %}
In modern Next, if not explicitly disabled, image files (including SVGs) are imported using [next/image](https://nextjs.org/docs/upgrading#nextconfigjs-customization-to-import-images).

You'll get a valid url by accessing the src property of the react component.

```tsx
import ArtworkDarkSvg from "@codegouvfr/react-dsfr/dsfr/artwork/dark.svg";

<svg>
    <use xlinkHref={`${ArtworkDarkSvg.src}#artwork-minor`} />
</svg>;
```

{% endtab %}
{% endtabs %}


# MUI integration

Use MUI components in your App or DSFRify your website build with MUI.

{% embed url="<https://youtu.be/FDRsx3N0OmY>" %}

react-dsfr features a DSFR theme for MUI. This enables you to use the [large library of MUI components](https://mui.com/) in your website, they will blend in nicely.

First of all you'll have to remove all usage of `<ThemeProvider />` and `createTheme()` from your codebase (if any) then implement the following approach:

```tsx
import MuiDsfrThemeProvider from "@codegouvfr/react-dsfr/mui";

function App() {

    return (
        <MuiDsfrThemeProvider>
            {/* your app ... */}
        </MuiDsfrThemeProvider>
    );
}
```

<details>

<summary>Custom variable in MUI theme</summary>

If you have [custom variables](https://mui.com/material-ui/customization/theming/#custom-variables) in your MUI theme implement the following approach.

In this example we have augmented the MUI theme so it was possible to call `theme.custom.isDarkModeEnabled`.

```tsx
import { createMuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { Theme } from "@mui/material/styles";

declare module "@mui/material/styles" {

    interface Theme {
        custom: {
            isDarkModeEnabled: boolean;
        }
    }
}

const { MuiDsfrThemeProvider } = createMuiDsfrThemeProvider({
    "augmentMuiTheme": ({ nonAugmentedMuiTheme, frColorTheme }) => ({
        ...nonAugmentedMuiTheme,
        "custom": {
            "isDarkModeEnabled": frColorTheme.isDark
        }
    })
});

function App() {

    return (
        <MuiDsfrThemeProvider>
            {/* your app ... */}
        </MuiDsfrThemeProvider>
    );
}
```

</details>

The demo setups for Vite, Next ans create-react-app all commes with MUI already setup.\
\
You can find aditional informations about this tool here:

{% embed url="<https://dsfr-connect.rame.fr/main/?path=/docs/dsfr-connect-utilisation-mui-v5--docs>" %}

### Next.js: Improving first print

In Next.js setup, on initial page load you may experience a few frames where MUI components aren't aware that the dark mode is enabled.

<figure><img src="/files/FFZt9EQs3NXoLQl3215P" alt=""><figcaption><p>Mui thinks we are in light mode</p></figcaption></figure>

<figure><img src="/files/EKTfxJ5ly3QIY7d1Jhdx" alt=""><figcaption><p>After idratation it switches to dark mode</p></figcaption></figure>

You can eradicate these few frames on subsequent page load by telling Next.js to perform SSR in the correct color scheme for the user:

<pre class="language-tsx" data-title="_app.tsx"><code class="lang-tsx">const { withDsfr, dsfrDocumentApi } = createNextDsfrIntegrationApi({
  defaultColorScheme: 'system',
<strong>  doPersistDarkModePreferenceWithCookie: true
</strong>});
</code></pre>

**Be aware**: this will opt you out[ from Automatic Static Optimization](https://nextjs.org/docs/messages/opt-out-auto-static-optimization), every hit of your website will trigger a complete render on the backend, so **it probably isn't worth it** unless you have already opted out from static optimization.

### Setting up Next.js + MUI + react-dsfr

{% hint style="warning" %}
Be aware that the API have changed since this video was recorded.
{% endhint %}

{% embed url="<https://youtu.be/0n0S6PcyG28>" %}

All demo setup are preconfigured with MUI installed.\
\\


# Custom Branding

Remove the governmental branding and apply your own theme.

By default, applications built with this toolkit must be deployed on a \`.gouv.fr\` domain. &#x20;

Using the DSFR outside that context requires an official agreement. &#x20;

But what if you want to open your app to other use cases?

**React-DSFR** allows you to white-label your application, and even apply a custom MUI theme dynamically, simply by changing a configuration value.

Here’s a video tutorial that shows how to leverage this feature:

{% embed url="<https://youtu.be/qd2kFXvrwps>" %}

You can find the template project used in the tutorial here:

{% embed url="<https://github.com/InseeFrLab/vite-insee-starter>" %}

**Bonus tip:** &#x20;

If you want to change the environment variable that defines the active theme \*\*without rebuilding\*\* (in Vite projects), you’ll find this tool very useful:

{% embed url="<https://github.com/garronej/vite-envs>" %}


# Storybook

Setting up Storybook in your react-dsfr project.

Storybook is an open-source tool for developing and testing UI components in isolation, allowing you to create and refine components independently from the app's business logic. &#x20;

For example [the components website of react-dsfr](https://components.react-dsfr.codegouv.studio/?path=/story/%F0%9F%87%AB%F0%9F%87%B7-introduction--page) is powered by Storybook.  \
\
Let's see how to setup Storybook 8 in your project. &#x20;

<figure><picture><source srcset="/files/FrnStKS2WJUYGvtriDXr" media="(prefers-color-scheme: dark)"><img src="/files/swElErQVUKUdhe9YzRpR" alt=""></picture><figcaption><p>The storybook of Lunatic-DSFR (INSEE, <a href="https://github.com/InseeFr/Lunatic-DSFR">https://github.com/InseeFr/Lunatic-DSFR</a>)</p></figcaption></figure>

## Minimal setup

If you use Storybook as an internal devloppement tool only. You don't need to customize much. &#x20;

First follow the official instruction to setup Storybook in your meta framework of choice: &#x20;

{% embed url="<https://storybook.js.org/docs/get-started/install>" %}

Here are the edit you need to apply to the default setup:  &#x20;

<pre class="language-json" data-title="package.json"><code class="lang-json">{
    // ...
    "scripts": {
        // ...
        "storybook": "storybook dev -p 6006",
        "build-storybook": "storybook build",
<strong>        "prestorybook": "react-dsfr update-icons",
</strong><strong>        "prebuild-storybook": "react-dsfr update-icons"
</strong>    }
}
</code></pre>

<pre class="language-tsx" data-title=".storybook/preview.tsx"><code class="lang-tsx">import type { Preview } from "@storybook/react";
<strong>import "@codegouvfr/react-dsfr/main.css";
</strong><strong>import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";
</strong>
<strong>startReactDsfr({
</strong><strong>    "defaultColorScheme": "system",
</strong><strong>    "useLang": () => "fr",
</strong><strong>});
</strong>

const preview: Preview = {
    parameters: {
        controls: {
            matchers: {
                color: /(background|color)$/i,
                date: /Date$/i
            }
        }
    }
};

export default preview;
</code></pre>

## Bells and whistles

If you wish to publish your storybook as component library showecase you might want to go the extra miles and customize the Manager to add top level darkMode switch, load the Marianne font, provide a language switch ect. &#x20;

If you want a fully DSFRised Storybook setup you can use this setup as reference:

{% embed url="<https://github.com/InseeFr/Lunatic-DSFR/tree/main/.storybook>" %}
You can see it live here: <https://inseefr.github.io/Lunatic-DSFR/storybook/>
{% endembed %}

Don't forget to add this extra dependency: &#x20;

{% tabs %}
{% tab title="npm" %}

```bash
npm install --save-dev storybook-dark-mode
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add --dev storybook-dark-mode
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add -D storybook-dark-mode
```

{% endtab %}

{% tab title="bun" %}

```bash
bun add --dev storybook-dark-mode
```

{% endtab %}
{% endtabs %}

Lastly apply the following reference `.storybook` directory in your setup. Be sure to carefully merge the `.storybook/main.ts` so you don't overwrite specific configuration required by your meta framework. &#x20;


# Analytics

Track your audience engagement and gain insights into how citizens interact with your website.

{% hint style="warning" %}
Message from the @gouvfr/dsfr team:&#x20;

La propriété de configuration `enableRating`, présente depuis la @gouvfr/dsfr:1.9.2, entraîne des envois de données très importants. Pour rappel, le modèle de facturation dépend du volume d'appels envoyés à Eulerian. Elle est retirée dans cette version @gouvfr/dsfr:1.10.2 (bundled with @codegouvfr/react-dsfr:[0.78.2](https://github.com/codegouvfr/react-dsfr/releases/tag/v0.78.2)). En remplacement, un attribut `data-fr-analytics-rating` peut être ajouté sur un élément dont on veut mesurer spécifiquement le taux de click. Il est important de s'assurer de la pertinence de chaque élément où cette fonctionnalité est activée afin d'optimiser l'envoi de données.
{% endhint %}

In the realm of analytics, the Service d'Information du Gouvernement (SIG) stipulates the utilization of [Eulerian](https://www.eulerian.com/). The vanilla JS/CSS module @gouvfr/dsfr, which powers this toolkit, is deeply integrated with the Eulerian platform.

Activating it equips you with the capabilities to accurately track user interactions with your application, including specific buttons they click and pages they navigate. To comply with GDPR regulations, it's crucial to request user consent before implementing this detailed level of tracking.

Presented here is an illustrative example demonstrating how to initialize the Eulerian integration and solicit user consent for its usage.

{% embed url="<https://github.com/garronej/react-dsfr-next-appdir-demo/blob/main/ui/consentManagement.tsx>" %}
Example Enabling Eulerian in Next.js App Router
{% endembed %}

You may refer to the documentation of the consentManagement utility via the following link:

{% embed url="<https://components.react-dsfr.codegouv.studio/?path=/docs/components-consentmanagement--default>" %}

To operate effectively, Eulerian requires certain parameters, which are provided upon initial registration on the Eulerian platform. This example includes only those. For a complete list and descriptions of accepted parameters, refer to the following link:

{% embed url="<https://github.com/codegouvfr/react-dsfr/blob/c3b7459732ac909530d998b0c233b366c958d0a1/src/eulerianAnalytics.ts#L3-L71>" %}
Type definition of the Eulerian params
{% endembed %}

In-depth documentation elaborating on all these parameters can be found here:

{% embed url="<https://github.com/GouvernementFR/dsfr/tree/main/src/analytics/doc/analytics>" %}
Documentation of the Eulerian integration into @gouvfr/dsfr
{% endembed %}

For efficient tracking of interactions with various website elements, it's essential that each DSFR component is assigned a unique ID. This allows you to distinguish between different elements via the Eulerian dashboard metrics.

Each component of the react-dsfr toolkit can be explicitly given an ID prop. In the event you don't assign one, react-dsfr will make an effort to generate comprehensible IDs that aid in component identification.


# Content-Security-Policy

Add security to you application

`react-dsfr` supports strict Content-Security-Policy headers.

### Nonce

{% embed url="<https://developer.mozilla.org/fr/docs/Web/HTML/Global_attributes/nonce>" %}

{% tabs %}
{% tab title="Vite" %}
Add your Content-Security-Policy either by configuring your server, or with the meta tag.\
Remember that a nonce **MUST be generated per requests**.\
\
Add the nonce to `react-dsfr`

<pre class="language-tsx" data-title="src/main.tsx" data-overflow="wrap"><code class="lang-tsx">import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";

<strong>const nonce = "123456789"; // you have to inject it on render
</strong><strong>startReactDsfr({ defaultColorScheme: "system", nonce });
</strong>
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  &#x3C;React.StrictMode>
    &#x3C;App />
  &#x3C;/React.StrictMode>
);
</code></pre>

To get the nonce, you have to enable SSR with Vite and either inject the value in `process.env` or in a additional custom meta tag in your `index.html`. You can also infer it by using the content of the Content-Security-Policy meta tag if you configured the header this way.\
For more information about SSR in Vite see the following page.

{% embed url="<https://vitejs.dev/guide/ssr.html>" %}
Vite SSR
{% endembed %}
{% endtab %}

{% tab title="Next.js App Router" %}
{% hint style="info" %}
This documentation is for [Next projects using the App router](https://nextjs.org/docs/app/building-your-application/routing).

You are in this case if you have a `app/` directory at the root of your project.
{% endhint %}

The following assumes that you configured your CSP accordingly [to the Next.js recommendation](https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy).

First configure the nonce in the `<DsfrHead />` tag in your root layout:

<pre class="language-tsx" data-title="app/layout.tsx"><code class="lang-tsx">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";
<strong>import { headers } from "next/headers";
</strong>
export default function RootLayout({ children }: { children: JSX.Element; }) {
<strong>  const nonce = headers().get("x-nonce") ?? undefined;
</strong>  //NOTE: The lang parameter is optional and defaults to "fr"
  const lang = "fr";
  return (
    &#x3C;html {...getHtmlAttributes({ defaultColorScheme, lang })} >
      &#x3C;head>
        &#x3C;StartDsfr />
<strong>        &#x3C;DsfrHead Link={Link} nonce={nonce} />
</strong>      &#x3C;/head>
      &#x3C;body>
        &#x3C;DsfrProvider lang={lang}>
          {children}
        &#x3C;/DsfrProvider>
      &#x3C;/body>
    &#x3C;/html>
  );
}
</code></pre>

The `X-Nonce` header is forwarded by the `middleware.ts` as suggested by Next.js.

{% hint style="warning" %}
It important to remember that reading headers in the root layout **turns all pages to dynamic rendering opt-in**. This is mandatory for nonce.
{% endhint %}

If you use the `NextAppDirEmotionCacheProvider`, don't forget to add the nonce to it accordingly to what Emotion and MUI needs: `<NextAppDirEmotionCacheProvider options={{ "key": "css", nonce, prepend: true }}>`

Then you have to tell `react-dsfr` to read and forward the nonce injected to all other scripts and styles by adding `doCheckNonce: true;` to the `startReactDsfr()` function:

<pre class="language-typescript" data-title="app/StartDsfr.tsx"><code class="lang-typescript">"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;
  }
}

<strong>startReactDsfr({ defaultColorScheme, Link, doCheckNonce: true });
</strong>
export function StartDsfr(){
  //Yes, leave null here.
  return null;
}
</code></pre>

{% endtab %}

{% tab title="Next.js Pages Router" %}
Next.js with old Pages Router is not supported. As per Next.js suggests, we recommended migrating to App Router.

{% embed url="<https://nextjs.org/docs/getting-started/installation#the-app-directory>" %}
App Router Migration
{% endembed %}
{% endtab %}

{% tab title="Create React App" %}
{% hint style="warning" %}
`Create React App` by itself is a way to build **static sites** which by definition cannot handle dynamic headers (like CSP) per request as no server will serve the pages.\
Before getting into nonce configuration, you have ponder whether or not you need that level of security within your static app, and if so, choosing a solution to generate and inject the nonce into your app.
{% endhint %}

Once your injected the nonce into your app, add the following code:

<pre class="language-tsx"><code class="lang-tsx">import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { startReactDsfr } from "@codegouvfr/react-dsfr/spa";

<strong>const nonce = "123456789" // have to be dynamic and injected
</strong><strong>startReactDsfr({ defaultColorScheme: "system", nonce });
</strong>
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  &#x3C;React.StrictMode>
    &#x3C;App />
  &#x3C;/React.StrictMode>
);
</code></pre>

{% endtab %}

{% tab title="Other" %}
Your framework isn't supported? Let's [get in touch](https://github.com/codegouvfr/dsfr-react)!
{% endtab %}
{% endtabs %}

### Trusted Types Policy

{% embed url="<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types>" %}

Trusted Types are supported out-of-the box.

When configuring your CSP you only have to add our policy names to your list:

<pre data-title="header configuration"><code>Content-Security-Policy:
    require-trusted-types-for 'script';
<strong>    trusted-types react-dsfr react-dsfr-asap;
</strong></code></pre>

We register two policies with only the `createHTML` hook. Policy names are `react-dsfr` and `react-dsfr-asap`

#### Custom policy name

You can configure a custom policy name if you need to by adding the `trustedTypesPolicyName` options to the `startReactDsfr()` function.

{% hint style="info" %}
In Next.js App Router, `trustedTypesPolicyName` must also be set to the `<DsfrHead />` component.
{% endhint %}

When a custom name is set, the suffix `-asap` is used for the second policy. Don't forget to add both to your header configuration.

**Example:**

If you set `trustedTypesPolicyName: "my-app"`

You header must be configured like so: `trusted-types my-app my-app-asap;`


# Publishing a NPM modules that depends on react-dsfr

You want to publish your own library of components that depends on react-dsfr?

Here is an example:

{% embed url="<https://github.com/EIG6-Geocommuns/geocommuns-core>" %}
A module that depend on react-dsfr and MUI
{% endembed %}

I recommend starting from ts-ci for any project meant to be published on NPM

{% embed url="<https://github.com/garronej/ts-ci>" %}

The main takeway:

* [@codegouv/react-dsfr must be a peer dependency of your project](https://github.com/EIG6-Geocommuns/geocommuns-core/blob/55e015a453a681a12bfa84624ccfd243ce8a6150/package.json#L48). Any app that would use your library would need to explicitely install react-dsfr. [For devloppement purpose, you want to add @codegouvfr/react-dsfr as devDependencies of your project](https://github.com/EIG6-Geocommuns/geocommuns-core/blob/55e015a453a681a12bfa84624ccfd243ce8a6150/package.json#L56).
* Do not add `"postinstall": "copy-dsfr-to-public"` in your library's package.json. It's the responsability of the host app to do so.
* If you rely on MUI, `@mui/material` `@emotion/styled` and `@emotion/react` should be peer dependencies as well. You should add those modules as devDependencies.
* If you use TSS: react-dsfr dosen't need to be a peerDependencies but @emotion/react does, you do not configure the emotion cache in your lib, that's the the responsability of the host app.


# Contributing

Thank you for your willingness to contribute, here is the guide: &#x20;

{% embed url="<https://github.com/codegouvfr/react-dsfr/blob/main/CONTRIBUTING.md>" %}


