Skip to main content

react-dsfr

Créer des interfaces React conformes au Design System de l'État français (DSFR) avec @codegouvfr/react-dsfr. Utiliser cette skill quand l'utilisateur demande de créer des pages, composants ou interfaces en React utilisant le DSFR, quand il mentionne react-dsfr, le design system de l'État, ou quand le projet utilise @codegouvfr/react-dsfr. Couvre les composants natifs react-dsfr (pas MUI), le routing, les icônes, les couleurs et les patterns de mise en page.

معلومات المصدر

المستودع
etalab-ia/skills
آخر نشاط في المصدر
٣ سبتمبر ٢٠٢٦ في ١٤:٤٩
لغة SKILL.md المكتشفة
الفرنسية
النجوم
٢٣
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
4 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
react-dsfr
description
Créer des interfaces React conformes au Design System de l'État français (DSFR) avec @codegouvfr/react-dsfr. Utiliser cette skill quand l'utilisateur demande de créer des pages, composants ou interfaces en React utilisant le DSFR, quand il mentionne react-dsfr, le design system de l'État, ou quand le projet utilise @codegouvfr/react-dsfr. Couvre les composants natifs react-dsfr (pas MUI), le routing, les icônes, les couleurs et les patterns de mise en page.
# react-dsfr Bibliothèque React pour le Design System de l'État français. Package : `@codegouvfr/react-dsfr`. ## Import pattern Chaque composant a son propre chemin d'import : ```tsx import { Button } from "@codegouvfr/react-dsfr/Button"; import { Alert } from "@codegouvfr/react-dsfr/Alert"; import { Card } from "@codegouvfr/react-dsfr/Card"; // etc. ``` ## Setup Next.js App Router > ⚠️ **Pattern obligatoire** : sans `getScriptToRunAsap()` dans `<head>`, le mode sombre cause un **flash blanc visible au chargement** (régression la plus courante). Le code ci-dessous est le minimum incompressible — ne pas écrire un `layout.tsx` plus simple. Pattern minimal en 3 fichiers (Next.js 14+ App Router, react-dsfr v1.30+), aligné sur le starter officiel react-dsfr (`dsfr-bootstrap`) : **1. `src/dsfr-bootstrap/defaultColorScheme.ts`** — constante partagée par le layout (serveur) et le provider (client) : ```tsx export const defaultColorScheme = "system" as const; ``` **2. `src/dsfr-bootstrap/index.tsx`** — wrapper `"use client"` qui importe `Link` : ```tsx "use client"; import { DsfrProviderBase, StartDsfrOnHydration, type DsfrProviderProps } from "@codegouvfr/react-dsfr/next-app-router"; import { defaultColorScheme } from "./defaultColorScheme"; import Link from "next/link"; declare module "@codegouvfr/react-dsfr/next-app-router" { interface RegisterLink { Link: typeof Link; } } export function DsfrProvider(props: DsfrProviderProps) { return ( <DsfrProviderBase defaultColorScheme={defaultColorScheme} Link={Link} {...props} /> ); } export { StartDsfrOnHydration }; ``` **3. `src/app/layout.tsx`** — composant serveur, ne passe au provider que des props sérialisables : ```tsx import { createGetHtmlAttributes } from "@codegouvfr/react-dsfr/next-app-router/getHtmlAttributes"; import { getScriptToRunAsap } from "@codegouvfr/react-dsfr/useIsDark/scriptToRunAsap"; import "@codegouvfr/react-dsfr/dsfr/dsfr.min.css"; import "@codegouvfr/react-dsfr/dsfr/utility/icons/icons.main.min.css"; import { DsfrProvider, StartDsfrOnHydration } from "../dsfr-bootstrap"; import { defaultColorScheme } from "../dsfr-bootstrap/defaultColorScheme"; const { getHtmlAttributes } = createGetHtmlAttributes({ defaultColorScheme }); export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html {...getHtmlAttributes({ lang: "fr" })}> <head> <script dangerouslySetInnerHTML={{ __html: getScriptToRunAsap({ defaultColorScheme, nonce: undefined, trustedTypesPolicyName: "react-dsfr", }), }} /> </head> <body> <DsfrProvider lang="fr"> {children} <StartDsfrOnHydration /> </DsfrProvider> </body> </html> ); } ``` **Pourquoi le wrapper `"use client"` ?** `layout.tsx` est un composant serveur ; `DsfrProviderBase` est un composant client (module `"use client"` dans le package). Le pattern officiel react-dsfr garde l'import de `Link` et la déclaration `RegisterLink` dans un module client dédié, le layout serveur ne passant que des props sérialisables (`lang`, `children`). `defaultColorScheme` vit dans son propre module (hors `"use client"`) car il est lu des deux côtés de la frontière serveur/client. **Trois éléments critiques** (ne pas omettre) : 1. **`createGetHtmlAttributes()`** : pose `data-fr-scheme` / `data-fr-theme` / `suppressHydrationWarning` sur `<html>` côté SSR 2. **`getScriptToRunAsap()` dans `<head>`** : script inline qui détecte le thème (localStorage ou `prefers-color-scheme`) **avant le premier paint CSS** — c'est lui qui élimine le flash. `nonce: undefined` ne vaut qu'en dev ; **sous CSP**, passer un `nonce` par requête (cf. [references/setup.md](references/setup.md#pattern-1--recommandé--sans-transpilepackages-imports-directs)) 3. **`StartDsfrOnHydration`** : re-scan du DOM après hydratation React pour bind les `Display`, modales, accordéons (sans ça, les boutons `aria-controls` sont muets au clic) **Noms react-dsfr v1.30+** : `DsfrProviderBase`, `StartDsfrOnHydration`, `createGetHtmlAttributes`, `DsfrHeadBase`. Les anciens noms (`DsfrProvider`, `StartDsfr`, `getHtmlAttributes`, `DsfrHead`) **n'existent plus dans le package** — ne pas les écrire. (Le wrapper local `DsfrProvider` créé ci-dessus est le nôtre, calqué sur le starter officiel — ce n'est pas un export du package.) Cette approche n'a **pas besoin de `transpilePackages`** dans `next.config.mjs` (les imports directs depuis `.../getHtmlAttributes` et `.../scriptToRunAsap` évitent le tree-shake de `DsfrHead.js` qui tire les `.woff2`). Pour les variantes (avec `DsfrHeadBase` + `transpilePackages`, icônes dynamiques via `iconId`, re-init manuelle DSFR), voir [references/setup.md](references/setup.md#nextjs-app-router). ## Routing et liens Enregistrer le composant `Link` du framework une seule fois au démarrage. Tous les composants react-dsfr utilisant `linkProps` s'en serviront automatiquement. - Liens internes : utilisent le routeur (client-side navigation) - URLs externes (`https://...`) : rendus comme `<a>` classiques - `href="#"` + `onClick` : convertis automatiquement en `<button>` accessible Voir [references/setup.md](references/setup.md) pour le setup par framework (Next.js, Vite, CRA). ## Utilitaire CSS : `fr.cx()` ```tsx import { fr } from "@codegouvfr/react-dsfr"; // Appliquer des classes utilitaires DSFR <div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}> <div className={fr.cx("fr-col-12", "fr-col-md-6")}>...</div> </div> // Spacing <div className={fr.cx("fr-mt-4w", "fr-mb-2w", "fr-p-3w")}>...</div> ``` ## Grille Le DSFR utilise une grille 12 colonnes : ```tsx <div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}> <div className={fr.cx("fr-col-12", "fr-col-md-6", "fr-col-lg-4")}>Col 1</div> <div className={fr.cx("fr-col-12", "fr-col-md-6", "fr-col-lg-4")}>Col 2</div> <div className={fr.cx("fr-col-12", "fr-col-lg-4")}>Col 3</div> </div> ``` Breakpoints : `sm` (576px), `md` (768px), `lg` (992px), `xl` (1248px). ## Icônes Deux familles d'icônes disponibles : - **DSFR** : `fr-icon-*` (ex: `"fr-icon-add-line"`, `"fr-icon-delete-fill"`, `"fr-icon-arrow-right-line"`) - **Remix Icon** : `ri-*` (ex: `"ri-account-box-line"`, `"ri-information-line"`) Les icônes sont typées : TypeScript offre l'autocomplétion. ## Couleurs et thème ```tsx import { useColors } from "@codegouvfr/react-dsfr/useColors"; function MyComponent() { const theme = useColors(); // theme.decisions.background.default.grey.default // theme.decisions.text.title.grey.default // theme.decisions.border.default.grey.default } ``` Le thème respecte automatiquement le mode clair/sombre, à condition que le setup du layout soit complet (cf. section "Setup Next.js App Router" plus haut). Le mode sombre est résolu côté SSR + script anti-flash dans `<head>` ; le `useColors()` lit ensuite la palette résolue. ## Pattern : page complète ```tsx import { Header } from "@codegouvfr/react-dsfr/Header"; import { Footer } from "@codegouvfr/react-dsfr/Footer"; import { Breadcrumb } from "@codegouvfr/react-dsfr/Breadcrumb"; import { fr } from "@codegouvfr/react-dsfr"; export function Page() { return ( <> <Header brandTop={<>RÉPUBLIQUE<br />FRANÇAISE</>} homeLinkProps={{ href: "/", title: "Accueil" }} serviceTitle="Mon service" /> <div className={fr.cx("fr-container", "fr-my-4w")}> <Breadcrumb homeLinkProps={{ href: "/" }} segments={[{ label: "Section", linkProps: { href: "/section" } }]} currentPageLabel="Page courante" /> <h1>Titre de la page</h1> {/* Contenu */} </div> <Footer accessibility="partially compliant" brandTop={<>RÉPUBLIQUE<br />FRANÇAISE</>} homeLinkProps={{ href: "/", title: "Accueil" }} /> </> ); } ``` ## Pattern : page avec menu latéral ```tsx <div className={fr.cx("fr-container", "fr-my-4w")}> <div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}> <div className={fr.cx("fr-col-12", "fr-col-md-4")}> <SideMenu title="Rubrique" burgerMenuButtonText="Menu" items={[ { text: "Page 1", linkProps: { href: "/p1" }, isActive: true }, { text: "Page 2", linkProps: { href: "/p2" } }, ]} /> </div> <div className={fr.cx("fr-col-12", "fr-col-md-8")}> {/* Contenu principal */} </div> </div> </div> ``` ## Pattern : formulaire ```tsx import { Input } from "@codegouvfr/react-dsfr/Input"; import { Select } from "@codegouvfr/react-dsfr/Select"; import { Checkbox } from "@codegouvfr/react-dsfr/Checkbox"; import { ButtonsGroup } from "@codegouvfr/react-dsfr/ButtonsGroup"; import { Alert } from "@codegouvfr/react-dsfr/Alert"; export function MyForm() { return ( <form> <Input label="Nom" nativeInputProps={{ required: true }} /> <Input label="Email" nativeInputProps={{ type: "email" }} /> <Select label="Département" nativeSelectProps={{ name: "dept" }}> <option value="" disabled hidden>Sélectionnez</option> <option value="75">Paris</option> </Select> <Checkbox legend="Préférences" options={[{ label: "Newsletter", nativeInputProps: { name: "newsletter" } }]} /> <ButtonsGroup inlineLayoutWhen="always" buttons={[ { children: "Envoyer", type: "submit" }, { children: "Annuler", priority: "secondary", type: "reset" }, ]} /> </form> ); } ``` ## Pattern : liste de cartes ```tsx <div className={fr.cx("fr-grid-row", "fr-grid-row--gutters")}> {items.map(item => ( <div key={item.id} className={fr.cx("fr-col-12", "fr-col-md-6", "fr-col-lg-4")}> <Card enlargeLink title={item.title} desc={item.description} linkProps={{ href: `/items/${item.id}` }} imageUrl={item.imageUrl} imageAlt={item.imageAlt} badge={<Badge severity="info">{item.category}</Badge>} /> </div> ))} </div> ``` ## Référence des composants Consulter [references/components.md](references/components.md) pour l'API complète de chaque composant : - **Layout** : Header, Footer, SideMenu, Breadcrumb, Pagination, Stepper
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub