@prokodo/ui
Version:
UI components for production-grade Next.js + Headless CMS (Strapi, Contentful, Headless WordPress) websites by prokodo β built for Core Web Vitals & SEO.
278 lines (212 loc) β’ 12.7 kB
Markdown
<p align="center">
<a href="https://www.prokodo.com" target="_blank" rel="noopener noreferrer">
<img src="https://cdn.prokodo.com/prokodo_logo_1a3bb7867c/prokodo_logo_1a3bb7867c.webp" alt="prokodo β UI component library for React" height="58" />
</a>
</p>
<h1 align="center">prokodo UI (Beta)</h1>
<h2 align="center">Empowering Digital Innovation</h2>
**Modern, customizable UI components built with React and TypeScript β developed by [prokodo](https://www.prokodo.com) for high-performance web interfaces.**
> πΊπΈ Need help shipping a production **Next.js + Headless CMS** in 4β6 weeks?
> **prokodo β Next.js CMS agency** β [click here](https://www.prokodo.com/en/solution/next-js-cms?utm_source=github&utm_medium=readme_top)
>
> π©πͺ Sie suchen eine **Next.js Agentur** (Strapi/Contentful/WP)?
> **prokodo β Next.js CMS Agentur** β [hier klicken](https://www.prokodo.com/de/loesung/next-js-cms?utm_source=github&utm_medium=readme_top)
[](https://www.npmjs.com/package/@prokodo/ui)
[](https://github.com/prokodo-agency/ui/actions/workflows/release.yml)
[](LICENSE)
[](https://ui.prokodo.com)
[](https://bundlephobia.com/result?p=@prokodo/ui)
---
- β¨ **Adaptive Island Components (AIC)**: A rendering strategy where each component loads only the JavaScript it needs β when needed.
- β‘οΈ **Modern stack**: Vite, React 19, TypeScript, and SCSS Modules
- π
**Design consistency**: Theming via design tokens and BEM-style naming
- π§© **Component-rich**: 40+ reusable UI components
- π§ͺ **Reliable**: Fully tested with Jest and Testing Library
- π **Storybook**: Explore the components at [ui.prokodo.com](https://ui.prokodo.com)
- π¦ **Ready-to-install**: Distributed via npm for non-production use under the BUSL-1.1 license
- π§± **Optimized for SSR**: Works great with Next.js and React Server Components
## β‘ Lightweight by Design
Adaptive Island Components (AIC) are fully modular and optimized for modern frameworks (Next.js, Remix, etc.).
Each component is built for **lazy loading**, works seamlessly with **React Server Components (RSC)**, and can be **tree-shaken** out when unused.
**Total bundle (all components): ~195β―kB gzipped**
- **Only 5β20β―kB** are typically loaded per page
- **Zero-JS on initial render** for most components
- **Hydration is deferred** until interaction or visibility
- Shared styles are minimal: **only ~16.5β―kB gzipped**
This makes `@prokodo/ui` ideal for modern SSR apps using Next.js or Remix, with excellent Time-to-Interactive (TTI) and Core Web Vitals.
---
## π Getting Started
### 1. Install the package
> β οΈ ESM-only: This package does not support CommonJS (`require()`).
```bash
pnpm add @prokodo/ui
# or
npm install @prokodo/ui
```
### 2. Use a component
#### React
```tsx
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function Layout() {
// Renders to HTML on the server with zeroβJS.
// On the client, it will hydrate when scrolled into view or the user interacts.
return <Button title="Click me"/>;
}
```
```tsx
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function Layout() {
// Renders to HTML on the server with zeroβJS.
// On the client, it will hydrate when scrolled into view or the user interacts.
return <Button title="Click me"/>;
}
```
```tsx
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function AboveTheFoldHero() {
// Because this lives above the fold, we want it to hydrate right away:
return <Button priority title="Welcome to prokodo"/>;
}
```
```tsx
"use client";
import { Button, type ButtonProps } from "@prokodo/ui/button";
import { type FC, memo } from "react";
// In a pureβclient file, you can wrap the AIC export.
// The `priority` prop here ensures hydration runs immediately when mounted.
export const HeadlineClient: FC<ButtonProps> = memo((props) => {
return <Button {...props} priority />;
});
```
```tsx
import { Headline, type ButtonProps } from "@prokodo/ui/button";
export default function GalleryPage() {
return (
<div style={{ height: "200vh" }}>
<p>Keep scrollingβ¦</p>
<div style={{ marginTop: "100vh" }}>
{/* This will render as HTML on the server;
on the client, it only hydrates when this element scrolls into view. */}
<Button title="I hydrate when you see me"/>
</div>
</div>
);
}
```
- β
= Available as AIC (renders zero-JS RSC and self-hydrates when needed) and can also be used as a clientβonly entry.
- \- = RSC (AIC) only; no clientβside bundle needed. (Usable in both, but best practice to use in RSC only)
| Component | β
AIC (RSC + optional client) | β
SSR-Compatible (`"use client"`) |
|-----------------------|:--------------------------------:|:---------------------------------:|
| Accordion | β
| β
|
| Animated | β
| β
|
| AnimatedText | β
| β
|
| Avatar | β
| β
|
| BaseLink | β
| β
|
| Button | β
| β
|
| Calendly | β
| β
|
| Card | β
| β
|
| Carousel | β
| β
|
| Chip | β
| β
|
| DatePicker | β
| β
|
| Dialog | β
| β
|
| Drawer | β
| β
|
| DynamicList | β
| β
|
| Form | β
| β
|
| FormResponse | β
| β |
| Grid/GridRow | β
| β |
| Headline | β
| - |
| Icon | β
| β |
| Image | β
| β |
| ImageText | β
| - |
| Input | β
| β
|
| Label | β
| β |
| Link | β
| β
|
| List | β
| β |
| Loading | β
| β |
| Lottie | β | β
|
| Map | β | β
|
| PostItem | β (Experimental - Coming soon) | β |
| PostTeaser | β (Experimental - Coming soon) | β |
| PostWidget | β (Experimental - Coming soon) | β |
| PostWidgetCarousel | β (Experimental - Coming soon) | - |
| ProgressBar | β
| β
|
| Quote | β
| β |
| RichText | β
| β
|
| Select | β
| β
|
| SideNav | β
| β
|
| Skeleton | β
| β |
| Slider | β
| β
|
| Snackbar & Provider | β
| β
|
| Stepper | β
| β
|
| Switch | β
| β
|
| Table | β
| β |
| Teaser | β
| - |
Island architecture lets you render components on the server and hydrate them on the client only when needed.
```tsx
import { createIsland } from '@prokodo/ui/createIsland';
import { NavbarServer } from './Navbar.server';
import type { NavbarProps } from './Navbar.model';
export const Navbar = createIsland<NavbarProps>({
name: 'Navbar',
Server: NavbarServer,
loadLazy: () => import('./Navbar.lazy'),
// Optional: Force client-side hydration as soon as someone uses an action
// We are automatically recognizing onChange, onKeyDown, ... events. Only needed for custom attributes.
isInteractive: (p: NavbarProps) => p.customEvent === true,
});
```
```tsx
'use client'
import { createLazyWrapper } from '@prokodo/ui/createLazyWrapper';
import { NavbarClient } from './Navbar.client';
import { NavbarServer } from './Navbar.server';
import type { NavbarProps } from './Navbar.model';
export default createLazyWrapper<NavbarProps>({
name: 'Navbar',
Client: NavbarClient,
Server: NavbarServer,
// Optional: Defer hydration until the component becomes visible in the viewport (Default: true)
// Can be controlled by priority attribute.
hydrateOnVisible: false,
// Optional: Force client-side hydration as soon as someone uses an action.
// We are automatically recognizing onChange, onKeyDown, ... events. Only needed for custom attributes.
isInteractive: (p: NavbarProps) => p.customEvent === true,
});
```
- [ ] Add more β¨ **fancy styling**, UI polish and properties
- [ ] Improve **accessibility** to meet **WCAG 2.2 AAA** standards
- [ ] Detailed Documentation about the components
- Next.js + **Strapi** content models
- Next.js + **Contentful** entries & preview
- Migration from **Headless WordPress** to Next.js
Compare CMS options β [Strapi vs Contentful vs Headless WP](https://www.prokodo.com/de/loesung/next-js-cms?utm_source=github&utm_medium=readme_examples)
Explore all components and examples in the official Storybook:
π https://ui.prokodo.com
```bash
pnpm i
pnpm dev
pnpm storybook
```
To build:
```bash
pnpm run build
pnpm run storybook:build
```
This library is published under the Business Source License 1.1 (BUSL-1.1).
Β© 2025 prokodo β All rights reserved.
Visit us at [prokodo.com](https://www.prokodo.com).