@epfl-sti/poesis
v0.6.9
Published
Poesis — EPFL Intranet React UI component library
Readme
Poesis
EPFL Intranet React UI component library — a themed, accessible component kit built with React, TypeScript, and Tailwind CSS v4.
Features
- 30+ components — buttons, inputs, cards, dialogs, toasts, tables, navigation shells, and more
- EPFL design tokens — colors, typography, spacing, shadows, and radii baked into Tailwind's
@theme - Dark mode — light / dark themes with a single
.darkclass toggle anduseThemehook - i18n ready — built-in EN/FR support via
react-i18next, with auseLanguagehook andLanguageSwitchercomponent - CSS auto-injection — styles are embedded in the JS bundle; no separate stylesheet import needed
- Fully typed — TypeScript declarations ship with the package
- Storybook — every component has interactive stories with accessibility checks
Installation
Bootstrap a new React + TypeScript app with Vite
If you don't have a project yet, scaffold one with Vite:
npm create vite@latest my-app -- --template react-ts
cd my-app
npm installThen install Poesis and its required peer dependencies:
npm install @epfl-sti/poesis @floating-ui/react i18next react-i18nextInstall optional peer dependencies as needed:
# Icons (used by many Poesis components)
npm install react-bootstrap-icons
# Routing
npm install react-router-dom
# Advanced select / combobox
npm install react-selectAdd to an existing project
npm install @epfl-sti/poesisPeer dependencies
Poesis expects the following packages in your project:
| Package | Version | Required |
| ----------------------- | ---------------------- | -------- |
| react | ^18.0.0 \|\| ^19.0.0 | yes |
| react-dom | ^18.0.0 \|\| ^19.0.0 | yes |
| @floating-ui/react | ^0.27.0 | yes |
| i18next | ^25.0.0 | yes |
| react-i18next | ^16.0.0 | yes |
| react-bootstrap-icons | ^1.11.0 | optional |
| react-router-dom | ^6.0.0 \|\| ^7.0.0 | optional |
| react-select | ^5.0.0 | optional |
Quick start
Here is an example of a basic Hello World page that uses PageShell for the EPFL look and feel, with a side-navigation menu, the LanguageSwitcher, and the ThemeToggle:
import { useState } from "react";
import { PageShell, ThemeToggle, LanguageSwitcher } from "@epfl-sti/poesis";
import type { NavCategory, NavSection } from "@epfl-sti/poesis";
const categories: NavCategory[] = [{ id: "home", label: "Home" }];
const sections: NavSection[] = [
{
id: "main",
title: "Navigation",
links: [
{ id: "welcome", label: "Welcome", href: "/" },
{ id: "about", label: "About", href: "/about" },
],
},
];
function App() {
const [activeLinkId, setActiveLinkId] = useState("welcome");
return (
<PageShell
categories={categories}
activeCategoryId="home"
sections={sections}
activeLinkId={activeLinkId}
onLinkClick={(href) => {
const link = sections.flatMap((s) => s.links).find((l) => l.href === href);
if (link) setActiveLinkId(link.id);
}}
actions={
<>
<LanguageSwitcher />
<ThemeToggle />
</>
}
>
<h1>Hello World 👋</h1>
<p>
<span style={{ textTransform: "capitalize" }}>{activeLinkId}</span> to your new app
powered by Poesis.
</p>
</PageShell>
);
}
export default App;No CSS import is needed — styles are injected automatically when you import any component.
Components
Primitives
Button · IconButton · Badge · Avatar · Spinner
Form Controls
Input · Textarea · Select · Checkbox · Switch · RadioGroup
Data Display
Card · Table · DescriptionList · EmptyState
Feedback
Alert · Dialog · ConfirmDialog · ToastProvider / useToast
Layout
PageShell · TopNav · SideNav · BurgerDrawer
Overlays & Navigation
DropdownMenu · Popover · Tooltip · Tabs
Theme & i18n
ThemeToggle · LanguageSwitcher
Hooks
| Hook | Description |
| ------------- | ------------------------------------------------ |
| useTheme | Current theme (light / dark) and toggle/set |
| initTheme | Initialise theme from localStorage / system pref |
| useLanguage | Current language (en / fr) and toggle/set |
| useAuth | Access the authenticated user and role setter |
| useToast | Imperatively add/remove toast notifications |
Theme utilities
epflSelectTheme— drop-inreact-selecttheme using EPFL design tokensepflSelectClassNames— Tailwind-based classNames config forreact-select
Development
Prerequisites
- Node.js 24 (see
.nvmrc) - npm
Scripts
# Install dependencies
npm install
# Start Storybook (development)
npm run storybook
# Build the library (dist/poesis.js + type declarations)
npm run build
# Build Storybook as a static site
npm run build-storybook
# Lint with ESLint
npm run lint
# Format with Prettier (4-space indent)
npm run format
# Check formatting (CI)
npm run format:check
# Build + run integration tests
npm run test:integrationProject structure
├── src/
│ ├── components/
│ │ ├── ui/ # Primitives, form controls, overlays
│ │ ├── layout/ # PageShell, TopNav, SideNav, BurgerDrawer
│ │ ├── data-display/ # Card, Table, DescriptionList, EmptyState
│ │ └── feedback/ # Alert, Dialog, ConfirmDialog, Toast
│ ├── hooks/ # useTheme, useLanguage, useAuth
│ ├── theme/ # react-select theme utilities
│ ├── i18n/ # i18next config + EN/FR translation files
│ ├── stories/ # Storybook stories
│ ├── pages/ # Demo app placeholder pages
│ ├── routes/ # Route config + role types
│ ├── lib.ts # Library entry point (public API)
│ └── index.css # Tailwind v4 @theme + design tokens
├── integration-tests/ # Consumer-simulation integration tests
├── .storybook/ # Storybook configuration
├── vite.config.ts # Vite lib mode + Tailwind + Storybook tests
├── tsconfig.lib.json # TypeScript config for .d.ts generation
├── PLAN.md # Implementation plan & phase tracker
└── STYLING.md # Full design system specificationBuilding the library
npm run buildThis runs two steps:
- Vite builds
src/lib.tsintodist/poesis.js(ESM, with CSS injected into JS) - TypeScript emits declaration files into
dist/(lib.d.ts+ per-component.d.ts)
Integration tests
A separate test project in integration-tests/ imports from the built dist/
exactly like a real consumer would. It renders components in a headless Chromium
browser via Vitest + Playwright and verifies exports, DOM output, CSS injection,
accessibility attributes, and component composition.
npm run test:integrationSee integration-tests/README.md for details.
Design system
The full design system specification — colors, typography, spacing, shadows,
theming strategy, layout architecture, and component inventory — is documented
in STYLING.md.
AI agent instructions
The package ships AGENT_INSTRUCTIONS.md — a comprehensive reference for AI coding agents (GitHub Copilot, Cursor, Claude Code, etc.) that covers every component, hook, type, design token, and common pattern in the library. It is included in the npm package and updates automatically when you run npm update.
Setup
Reference the file in your project's agent configuration so your AI assistant always has accurate, up-to-date context about Poesis.
GitHub Copilot — add to .github/copilot-instructions.md:
For using the @epfl-sti/poesis component library, follow the instructions in:
@file:node_modules/@epfl-sti/poesis/AGENT_INSTRUCTIONS.mdCursor — create a rule file in .cursor/rules/poesis.mdc:
---
description: Instructions for using the @epfl-sti/poesis component library
globs:
alwaysApply: true
---
@file:node_modules/@epfl-sti/poesis/AGENT_INSTRUCTIONS.mdOther agents — include the file path node_modules/@epfl-sti/poesis/AGENT_INSTRUCTIONS.md in your agent's context or system prompt.
Authors
- Andrii Babarytskyi
- Juan Convers
Assisted by Claude Opus 4.6
License
Licensed under the Apache License, Version 2.0. See LICENSE for the full text.
