prokodo UI (Beta)
Empowering Digital Innovation
Modern, customizable UI components built with React and TypeScript — developed by prokodo for high-performance web interfaces.

✨ Features
- ✨ 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
- 📦 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
Addaptial 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()
).
pnpm add @prokodo/ui
npm install @prokodo/ui
2. Use a component
React
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function Layout() {
return <Headline title="Click me"/>;
}
Next.js (RSC + AIC, lazy‐hydrate when visible/interacted)
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function Layout() {
return <Headline title="Click me"/>;
}
Next.js (RSC + AIC, force immediate hydration with priority)
import { Button, type ButtonProps } from "@prokodo/ui/button";
export default function AboveTheFoldHero() {
return <Button priority title="Welcome to prokodo"/>;
}
Next.js ("use client" wrapper, immediate hydration - above the fold)
"use client";
import { Button, type ButtonProps } from "@prokodo/ui/button";
import { type FC, memo } from "react";
export const HeadlineClient: FC<ButtonProps> = memo((props) => {
return <Button {...props} priority />;
});
Next.js (hydrate on visibility only, default behavior)
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 Components
Compatibility of the components
- ✅ = Available as AIC (renders zero-JS RSC and self-hydrates when needed) and can also used as a client‐only entry.
- - = RSC (AIC) only; no client‐side bundle needed. (Useable in both, but best practice to use in RSC only)
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 | ✅ | - |
How to create my own Island Component?
1. Create your island component (Navbar.tsx):
Island architecture lets you render components on the server and hydrate them on the client only when needed.
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'),
isInteractive: (p: NavbarProps) => p.customEvent === true,
});
2. Create your lazy wrapper (Navbar.lazy):
'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,
hydrateOnVisible: false,
isInteractive: (p: NavbarProps) => p.customEvent === true,
});
🎯 Next steps
📘 Documentation
Explore all components and examples in the official Storybook:
👉 https://ui.prokodo.com
🛠 Local Development
pnpm i
pnpm dev
pnpm storybook
To build:
pnpm run build
pnpm run storybook:build
📄 License
This library is published under the Business Source License 1.1 (BUSL-1.1).
© 2025 prokodo — All rights reserved.
Visit us at prokodo.com.