Official UI Kit for La Suite numérique - A modern, accessible, and customizable React component library built on Cunningham.
- Introduction
- Features
- Technologies
- Prerequisites
- Installation
- Quick Start
- Project Structure
- Available Components
- Themes
- Hooks
- Internationalization
- Storybook Documentation
- Development
- Customization
- Usage Examples
- Compatibility
- Contributing
- License
@gouvfr-lasuite/ui-kit is the official design system for La Suite numérique, the French government's collaborative tools ecosystem. This library provides a consistent set of reusable, accessible React components that comply with governmental design standards.
Built on top of Cunningham (v4), this kit extends the design system capabilities with components specific to La Suite numérique needs.
- Visual Consistency: Ensure a uniform user experience across all La Suite numérique products
- Accessibility: Comply with WCAG and RGAA standards for maximum accessibility
- Performance: Optimized and tree-shakable components
- Flexibility: Support for multiple themes (DSFR, ANCT, White Label)
- Developer-friendly: Native TypeScript, comprehensive documentation, easy integration
- 25+ components ready to use
- Multiple themes: DSFR, ANCT, White Label (light/dark)
- Accessibility: Keyboard navigation, screen readers, ARIA
- Internationalization: Built-in French and English support
- Responsive: Adaptive components with dedicated hooks
- Layouts: Page layout system with resizable panels
- La Gaufre Integration: Component for La Suite numérique services integration
- TypeScript: Full typing for better DX
- Design tokens: Customizable CSS/SCSS/TS token system
| Technology | Version | Usage |
|---|---|---|
| React | 19.x | UI Framework |
| TypeScript | 5.6 | Static typing |
| Vite | 6.x | Bundler / Dev server |
| Cunningham | 4.1 | Base design system |
| Storybook | 8.5 | Documentation / Playground |
| Sass | 1.83 | CSS preprocessor |
| Vitest | 2.1 | Unit testing |
| react-aria-components | 1.8 | Accessible primitives |
| react-resizable-panels | 2.1 | Resizable panels |
| dnd-kit | 6.3 | Drag and Drop |
- Node.js: >= 20.x
- Package manager: yarn (recommended) or npm
- React: 19.x
yarn add @gouvfr-lasuite/ui-kitnpm install @gouvfr-lasuite/ui-kitMake sure you have the peer dependencies installed:
yarn add react react-domIn your entry file (e.g., main.tsx or App.tsx):
// UI Kit styles (includes Cunningham)
import "@gouvfr-lasuite/ui-kit/style";
// Optional: Marianne font
import "@gouvfr-lasuite/ui-kit/fonts/Marianne";Wrap your application with the CunninghamProvider:
import { CunninghamProvider } from "@gouvfr-lasuite/ui-kit";
function App() {
return (
<CunninghamProvider>
<YourApp />
</CunninghamProvider>
);
}import { MainLayout, QuickSearch, TreeView } from "@gouvfr-lasuite/ui-kit";
function MyPage() {
return (
<MainLayout
leftPanelContent={<TreeView data={treeData} />}
>
<QuickSearch placeholder="Search..." />
{/* Your content */}
</MainLayout>
);
}ui-kit/
├── src/
│ ├── components/ # React components
│ │ ├── badge/ # Badge
│ │ ├── button/ # Buttons (ProConnect)
│ │ ├── datagrid/ # Data grid
│ │ ├── dnd/ # Drag and Drop
│ │ ├── dropdown-menu/ # Dropdown menu
│ │ ├── filter/ # Filters
│ │ ├── footer/ # Footer
│ │ ├── form/ # Form fields
│ │ ├── hero/ # Hero section
│ │ ├── icon/ # Icons
│ │ ├── la-gaufre/ # La Suite integration
│ │ ├── language/ # Language selector
│ │ ├── layout/ # Layouts and panels
│ │ ├── loader/ # Loading indicators
│ │ ├── modal/ # Modals
│ │ ├── Provider/ # Cunningham Provider
│ │ ├── quick-search/ # Quick search
│ │ ├── separator/ # Separators
│ │ ├── share/ # Sharing and permissions
│ │ ├── tabs/ # Tabs
│ │ ├── tooltip/ # Tooltips
│ │ ├── tree-view/ # Tree view
│ │ └── users/ # User avatars and menus
│ ├── hooks/ # Custom React hooks
│ ├── locales/ # Translation files
│ ├── styles/ # Global styles and variables
│ ├── assets/ # Resources (fonts, images)
│ └── utils/ # Utilities
├── .storybook/ # Storybook configuration
├── cunningham.ts # Design tokens configuration
└── dist/ # Production build
| Component | Description |
|---|---|
MainLayout |
Main layout with header and resizable panels |
Header |
Application header |
LeftPanel |
Left side panel (navigation) |
RightPanel |
Right side panel (details) |
Footer |
Official footer |
Tabs |
Tab navigation |
DropdownMenu |
Contextual dropdown menu |
| Component | Description |
|---|---|
Input |
Text input field |
Textarea |
Multi-line text area |
Select |
Selection list |
Checkbox |
Checkbox |
Radio |
Radio button |
Switch |
Toggle switch |
Label |
Field label |
| Component | Description |
|---|---|
TreeView |
Interactive tree view with pagination |
Datagrid |
Data grid |
QuickSearch |
Quick search bar (cmd+k) |
Badge |
Status badge |
Icon |
Material icons |
Loader |
Loading indicator |
Tooltip |
Tooltip |
| Component | Description |
|---|---|
ShareModal |
Share modal with access management |
UserAvatar |
User avatar |
UserMenu |
User menu with logout |
UsersInvitation |
User invitation |
| Component | Description |
|---|---|
LaGaufre |
La Suite numérique services menu |
LaGaufreV2 |
Enhanced version of La Gaufre |
ProConnectButton |
ProConnect login button |
| Component | Description |
|---|---|
Modal |
Generic modal |
Separator |
Visual separator |
Hero |
Hero section |
Filter |
Filter component |
LanguageSelector |
Language selector |
The UI Kit supports multiple predefined themes:
| Theme | Description |
|---|---|
default |
White Label - Light mode |
dark |
White Label - Dark mode |
dsfr-light |
French State Design System - Light mode |
dsfr-dark |
French State Design System - Dark mode |
anct-light |
ANCT - Light mode |
anct-dark |
ANCT - Dark mode |
import { CunninghamProvider, cunninghamConfig } from "@gouvfr-lasuite/ui-kit";
// Use a predefined theme
<CunninghamProvider theme="dsfr-light">
<App />
</CunninghamProvider>see Cunningham docs for more information
Detects responsive breakpoints:
import { useResponsive } from "@gouvfr-lasuite/ui-kit";
function MyComponent() {
const { isMobile, isTablet, isDesktop } = useResponsive();
return isDesktop ? <DesktopView /> : <MobileView />;
}Override default translations:
import { useCustomTranslations } from "@gouvfr-lasuite/ui-kit";
// In your Provider
const customTranslations = {
"en-US": {
components: {
share: {
modalTitle: "Share this document",
},
},
},
};The UI Kit natively supports French and English.
fr-FR- French (default)en-US- English
<CunninghamProvider currentLanguage="en-US">
<App />
</CunninghamProvider>- Create a new translation file in
src/locales - Add all translations
- Create a PR
import { locales } from "@gouvfr-lasuite/ui-kit";
const customLocales = {
...locales,
"de-DE": {
components: {
share: {
modalTitle: "Teilen",
// ...
},
},
},
};
<CunninghamProvider customLocales={customLocales}>
<App />
</CunninghamProvider>Interactive documentation is available via Storybook.
yarn storybookThen access http://localhost:6006
yarn install| Script | Description |
|---|---|
yarn dev |
Start Vite development server |
yarn build |
Build library for production |
yarn lint |
Check code with ESLint |
yarn test |
Run tests with Vitest |
yarn storybook |
Start Storybook (port 6006) |
yarn build-storybook |
Build Storybook for deployment |
yarn build-theme |
Generate CSS/SCSS/TS token files |
# Tests in watch mode
yarn test
# Tests with coverage
yarn test --coveragesrc/components/my-component/
├── index.tsx # Main export
├── index.scss # Component styles
├── MyComponent.tsx # React component
├── types.ts # TypeScript types
└── my-component.stories.tsx # Storybook stories
Design tokens are defined in cunningham.ts and can be overridden:
// Available tokens
{
globals: {
font: { sizes, weights, families },
spacings: { xs, sm, md, lg, xl, ... },
colors: { brand-*, gray-*, info-*, success-*, warning-*, error-* },
breakpoints: { xxs, xs, mobile, tablet },
},
contextutals: {
background: {
semantic: {
brand: {
primary: '..'
}
}
}
}
}Tokens are exposed as CSS variables:
.my-custom-element {
color: var(--c--globals--colors--brand-500);
padding: var(--c--globals--spacings--md);
font-size: var(--c--globals--font--sizes--lg);
background: var(--c--contextuals--background--semantic--brand--primary);
}<!-- Colors -->
<div class="clr-green-500">Primary text</div>
<div class="bg-success-500">Secondary background</div>
<!-- Spacing -->
<div class="p-md">Medium padding</div>
<div class="m-lg">Large margin</div>import {
CunninghamProvider,
MainLayout,
TreeView,
QuickSearch,
UserMenu,
} from "@gouvfr-lasuite/ui-kit";
import "@gouvfr-lasuite/ui-kit/style";
const treeData = [
{
id: "1",
name: "Documents",
children: [
{ id: "1-1", name: "Report.pdf" },
{ id: "1-2", name: "Notes.md" },
],
},
];
function App() {
return (
<CunninghamProvider>
<MainLayout
icon={<Logo />}
leftPanelContent={
<TreeView
data={treeData}
onSelect={(node) => console.log(node)}
/>
}
rightHeaderContent={
<UserMenu
user={{ name: "John Doe", email: "john@example.com" }}
onLogout={() => {}}
/>
}
>
<QuickSearch
onSearch={(query) => console.log(query)}
groups={[
{
title: "Recent documents",
items: [
{ id: "1", label: "Q4 Report" },
{ id: "2", label: "Budget 2024" },
],
},
]}
/>
<main>Main content</main>
</MainLayout>
</CunninghamProvider>
);
}import { ShareModal } from "@gouvfr-lasuite/ui-kit";
function ShareButton() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>Share</button>
<ShareModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
members={[
{ id: "1", name: "Marie", email: "marie@example.com", role: "editor" },
]}
onAddMember={(user, role) => {}}
onRemoveMember={(userId) => {}}
onCopyLink={() => navigator.clipboard.writeText(window.location.href)}
/>
</>
);
}import { Input, Select, Switch, Label } from "@gouvfr-lasuite/ui-kit";
function ContactForm() {
return (
<form>
<div>
<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="Your name" required />
</div>
<div>
<Label htmlFor="department">Department</Label>
<Select
id="department"
options={[
{ value: "hr", label: "Human Resources" },
{ value: "tech", label: "Technology" },
{ value: "admin", label: "Administration" },
]}
/>
</div>
<div>
<Switch id="newsletter" />
<Label htmlFor="newsletter">Subscribe to newsletter</Label>
</div>
</form>
);
}| Browser | Version |
|---|---|
| Chrome | Last 2 versions |
| Firefox | Last 2 versions |
| Safari | Last 2 versions |
| Edge | Last 2 versions |
- React: 19.x (peer dependency)
- Next.js: 14+ (with appropriate configuration)
- Remix: Compatible
- Vite: Optimized
- WCAG 2.1 Level AA compliant
- RGAA 4.1 compliant
- Full keyboard navigation
- Screen reader support (NVDA, VoiceOver, JAWS)
Contributions are welcome! See the CONTRIBUTING.md file for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Commit your changes (follow commit conventions)
- Push the branch (
git push origin feature/my-feature) - Open a Pull Request
This project follows conventional commit conventions:
type(scope): description
# Examples
feat(tree-view): add pagination support
fix(modal): resolve focus trap issue
docs(readme): update installation section
See CONTRIBUTING.md for the release process.
This project is licensed under the MIT License. See the LICENSE file for details.
- Issues: GitHub Issues
- Documentation: Storybook
- Cunningham: Cunningham Documentation
Made with care for La Suite numérique
A French government initiative