Quick Start
Get started with roi-ui components in minutes
Prerequisites
roi-ui components are built on top of Base UI. You'll need to install Base UI first to use these components.
Installation
1. Install Base UI
npm install @base-ui/react
2. Set up portals
Add a portal container to your root layout:
layout.tsx
<body>
<div className="root">
{children}
</div>
</body>
3. Add global styles
Copy and paste the global CSS variables into your globals.css file:
globals.css
:root {
--radius: 0.6rem;
--radius-lg: 1rem;
--background: oklch(0.9757 0.002 220);
--foreground: oklch(0.35 0.008 220);
--title: oklch(0.12 0.01 220);
--title-hover: oklch(0.08 0.012 220);
--card: oklch(1 0 0);
--card-foreground: oklch(0.18 0.005 220);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.18 0.005 220);
--dialog-overlay: oklch(0 0 0 / 0.4);
--dialog-z: 100;
--primary: oklch(0.1855 0.0326 233.92);
--primary-foreground: oklch(0.99 0.002 220);
--secondary: oklch(0.9283 0.0024 228.93);
--secondary-foreground: oklch(0.3149 0.006 220);
--muted: oklch(0.9771 0 228.93);
--muted-foreground: oklch(0.6878 0.0367 271.46);
--accent: oklch(0.9457 0.01 248.76);
--accent-foreground: oklch(0.32 0.015 280);
--border: oklch(0.9166 0.003 220);
--input: oklch(0.98 0.002 220);
--ring: oklch(0.42 0.05 240);
--surface: oklch(0.985 0.002 220);
--surface-foreground: oklch(0.38 0.006 220);
--shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.02);
--shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.05), 0 4px 6px -2px oklch(0 0 0 / 0.02);
--linenumber: oklch(0.7604 0 0 / 60%);
--destructive: oklch(0.6553 0.1374 15.66);
--destructive-foreground: oklch(0.9808 0.009 23.81);
--success: oklch(0.722 0.1946 146.7);
--success-foreground: oklch(0.9505 0.0792 149.64);
--warning: oklch(0.8782 0.0981 74.65);
--warning-foreground: oklch(0.5784 0.105 81.04);
--info: oklch(0.7091 0.15 264.71);
--info-foreground: oklch(0.7091 0.15 264.71);
--selection-bg: oklch(0.1855 0.0326 233.92);
--selection-text: oklch(0.8985 0.0098 252.82);
--chart1: oklch(0.5759 0.1503 264.31);
--chart2: oklch(0.4819 0.1788 263.5);
--easeOut: cubic-bezier(0, 0.958, 0.858, 1.024);
}
[data-theme="dark"] {
--background: oklch(0.1704 0.0106 284.91);
--foreground: oklch(0.94 0.003 220);
--text: oklch(0.82 0.005 220);
--title: oklch(0.96 0.002 220);
--title-hover: oklch(0.98 0.001 220);
--card: oklch(0.1955 0.0126 284.91);
--card-foreground: oklch(0.94 0.003 220);
--popover: oklch(0.13 0.012 240);
--popover-foreground: oklch(0.94 0.003 220);
--primary: oklch(0.8985 0.0098 252.82);
--primary-foreground: oklch(0.08 0.008 240);
--secondary: oklch(0.2762 0.0243 274.47);
--secondary-foreground: oklch(0.88 0.004 220);
--muted: oklch(0.2455 0.0126 284.91);
--muted-foreground: oklch(0.5247 0.0228 279.03);
--accent: oklch(0.2612 0.015 280);
--accent-foreground: oklch(0.85 0.008 280);
--border: oklch(0.2949 0.0143 274.47);
--input: oklch(0.2329 0.0143 274.47);
--ring: oklch(0.78 0.08 240);
--surface: oklch(0.12 0.01 240);
--surface-foreground: oklch(0.78 0.005 220);
--shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.15);
--shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.25), 0 4px 6px -2px oklch(0 0 0 / 0.15);
--linenumber: oklch(0.7604 0 0 / 30%);
--destructive: oklch(0.5219 0.1656 18.34);
--destructive-foreground: oklch(0.8988 0.0447 17.32);
--success: oklch(0.8325 0.2177 151.25);
--success-foreground: oklch(0.5299 0.147 149.1059);
--warning: oklch(0.829 0.105 81.04);
--warning-foreground: oklch(0.5893 0.1083 78.11);
--info: oklch(0.7091 0.15 264.71);
--info-foreground: oklch(0.7091 0.15 264.71);
--selection-bg: oklch(0.8985 0.0098 252.82);
--selection-text: oklch(0.1855 0.0326 233.92);
--chart1: oklch(0.6487 0.1856 264.84);
--chart2: oklch(0.4187 0.2556 267.84);
}
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
*:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 2px;
}
html,
body {
max-width: 100vw;
overflow-x: hidden;
background-color: var(--background);
color: var(--foreground);
}
a {
color: inherit;
text-decoration: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--title);
font-weight: 600;
line-height: 1.2;
}
p {
margin-top: 1.5rem;
margin-bottom: 1.5rem;
}
/* Special margin for TSX file copy instruction - targets paragraph immediately before ComponentSource wrapper with TSX */
p:has(+ div .container[data-tsx="true"]) {
margin-top: 48px;
margin-bottom: 16px;
}
input,
button,
textarea,
select {
font: inherit;
}
.root {
isolation: isolate;
}
.main-content {
padding-top: var(--header-height);
}
@media (max-width: 1023px) {
.main-content {
padding-top: var(--header-height);
}
}
::selection {
background-color: var(--selection-bg);
color: var(--selection-text);
}
::-moz-selection {
background-color: var(--selection-bg);
color: var(--selection-text);
}
Your first component
Once you have Base UI set up, you can start using roi-ui components. Here's a simple button example:
button-demo.tsx
import { Button } from "@/components/ui/button/button";
export default function ButtonDemo() {
return <Button>Button</Button>;
}