A modern, accessible UI component library for library contexts and web applications. Developed at the Service Center for Digital Humanities (SCDH) at the University of MΓΌnster.
With the integration of Design Tokens (compatible with Penpot) and Tailwind CSS, this library provides a highly flexible foundation for consistent user interfaces.
The library consists of base components, SCDH-specific components, and two Composites (aggregations of multiple components that demonstrate how they work together).
These components live in src/components/ui/ and form the fundamental building blocks:
| Component | Description |
|---|---|
Accordion |
Collapsible content sections. |
Badge |
Small status or label elements. |
Button |
Buttons in various variants. |
Card |
Container for grouped content. |
Checkbox |
Multi-select field. |
Field |
Form field with label, description, and error state. |
Input |
Single-line input field. |
Label |
Label for form elements. |
RadioGroup |
Group of single-select fields. |
Separator |
Visual divider. |
Sheet |
Side overlay panel (e.g., for mobile navigation). |
TreeView |
Hierarchical representation of data (base variant). |
These components live in src/components/ui/scdh/ and are tailored to the requirements of library and digital humanities systems:
| Component | Description |
|---|---|
TreeView |
Hierarchical representation of collections or classifications (SCDH variant with custom icons and defaults). |
PageView |
Standardized layouts for detail and list views. |
SearchBar |
Optimized search fields for library portals. |
Facet |
A single facet for filtering search results. |
ListItem |
List entry with tags and actions. |
Header |
Header with logo and title (HeaderLogo, HeaderTitle). |
Menubar |
Navigation bar (MenubarItems, MenubarItem, MenubarActions). |
Sidebar |
Sidebar (SidebarToggle, SidebarContent). |
Footer |
Footer. |
Composites bundle multiple components into a cohesive, reusable building block:
| Composite | Description |
|---|---|
FacetSearch |
Complete faceted search: combines SearchBar, Facet, and ListItem with a search service (SearchServiceProvider, useSearchService, useSearchFacets). |
AppLayout |
Complete app layout: combines Header, Menubar, Sidebar, Footer, and a responsive Sheet for mobile navigation. |
- Node.js (current LTS version)
- pnpm (recommended, see pnpm.io/motivation)
Installing pnpm:
# Linux / macOS
curl -fsSL https://get.pnpm.io/install.sh | sh -
# Windows (PowerShell)
Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression# Install dependencies
pnpm install
# Start Storybook (interactive development environment)
pnpm run storybookThen open http://localhost:6006 to see the components.
| Command | Description |
|---|---|
pnpm run storybook |
Starts Storybook with Hot Module Replacement. |
pnpm run build |
Builds the NPM package (library build) into dist/. |
pnpm run build:app |
Builds the demo app. |
pnpm run lint |
Runs ESLint. |
pnpm test |
Runs the Vitest tests (including Storybook interaction tests). |
pnpm tokens:build |
Transforms and integrates design tokens (see the Design section). |
Each component has a .stories.tsx file in src/stories/. These define the various states (stories) of the component. Changes are immediately visible in Storybook via Hot Module Replacement.
In addition, we use Play functions in the stories to automatically simulate complex user interactions. These interaction tests are run via Vitest:
# Run all tests
pnpm test
# Test a specific file
pnpm test path/to/file.stories.tsxFor more details, see CONTRIBUTING.md.
This repository is the basis for an NPM package. You can use the components directly in your own app.
pnpm add @scdh_muenster/ui-componentsImport the compiled styles in your app entry point:
import '@scdh_muenster/ui-components/styles.css'import { Button, Badge, SearchBar, FacetSearch } from '@scdh_muenster/ui-components'
export function MyApp() {
return (
<div>
<Button>Let's go</Button>
<Badge>New</Badge>
<SearchBar onSearch={(query) => console.log(query)} />
</div>
)
}- The library uses Tailwind CSS 4 with CSS-first theme configuration. No consumer-side Tailwind config preset is required.
reactandreact-domare peer dependencies and must be present in your app (version^18or^19).- The styles are provided via
@scdh_muenster/ui-components/styles.css.
The library uses Tailwind CSS 4 with CSS-first theme configuration. The theme variables are defined in src/styles.css via @theme inline and exposed as utility classes:
@theme inline {
--color-scdh-blue-500: hsl(var(--scdh-blue-500));
}In code, you then use the generated utility classes:
<button className="bg-scdh-blue-500 text-white rounded-lg px-4 py-2">
Action
</button>No separate Tailwind config file is needed β everything runs through the CSS variables in styles.css.
src/styles.css is the single source of truth for the design system. It contains:
@import "tailwindcss"and@import "tw-animate-css"@theme inlinemappings (CSS variables β Tailwind utilities)@font-facedefinitions (e.g.,Metawebpro,WWU Symbol)@layer basewith:rootand.darkvariables (colors, radii, etc.)
β οΈ Important:src/styles.cssis automatically generated bydesign_system/scripts/integrate-tokens.tsand must not be edited manually β changes will be overwritten. Instead, editsrc/styles.template(base styles and shadcn/ui configuration).
The importer from a design system tool (currently PenPot) lives in the design_system/ directory. Here's how the import works:
-
Export tokens: Export your design tokens from PenPot as a JSON file.
-
Place the JSON: Save the file as
tokens.jsonindesign_system/input/. -
Run the build script:
pnpm tokens:build
This runs two scripts:
tokens:transform(design_system/scripts/transform-tokens.ts): Converts the tokens into CSS variables and Tailwind theme variables.tokens:integrate(design_system/scripts/integrate-tokens.ts): Integrates the generated tokens intosrc/styles.css.
-
Result:
- The generated CSS variables land in
design_system/output/generated-tokens.css. - The Tailwind theme variables are written into
src/styles.css.
- The generated CSS variables land in
-
Verify: Check the changes afterwards in Storybook.
- Styling via Tailwind classes: Components are styled with Tailwind utility classes, not their own CSS files.
cn()utility: Use thecn()function fromsrc/lib/utils.tsto combine classes intelligently and avoid conflicts.- Accessibility: The components are based on proven patterns (including Radix UI). Keep the underlying ARIA attributes and keyboard navigation intact.
- Design tokens: Use central tokens (e.g.,
bg-scdh-blue-500) instead of hardcoded colors to keep the design consistent. - Maintain stories: Every new or changed component should have a
.stories.tsxfile insrc/stories/so the component is documented and tested in Storybook.