Guides
Remix Setup
Integrate trink-ui into your Remix application with server-side rendering support.
Prerequisites
- Remix v2 or React Router v7 (Remix successor)
- React 18 or 19
- Tailwind CSS v4
- Node.js 18+
1Install the package
pnpm add @trinkui/reactnpm install @trinkui/react2Configure Remix
Add @trinkui/react to serverDependenciesToBundle so Remix can process the ESM package on the server:
/** @type {import("@remix-run/dev").AppConfig} */
export default {
serverDependenciesToBundle: [
"@trinkui/react",
"@trinkui/shared",
],
};If you are using React Router v7 (the Remix successor), no special config is needed since it uses Vite under the hood and handles ESM natively.
3CSS setup in root.tsx
Import your global CSS file containing the trink-ui variables in your root route. The CSS file should include the Tailwind source directive and all theme variables:
import type { LinksFunction } from "@remix-run/node";
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import styles from "./styles/globals.css?url";
export const links: LinksFunction = () => [
{ rel: "stylesheet", href: styles },
];
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}@import "tailwindcss";
@source "node_modules/@trinkui/react/src";
:root {
--trinkui-bg: 255 255 255;
--trinkui-fg: 10 10 10;
--trinkui-primary: 99 102 241;
--trinkui-primary-fg: 255 255 255;
--trinkui-secondary: 241 245 249;
--trinkui-secondary-fg: 15 23 42;
--trinkui-accent: 249 115 22;
--trinkui-muted: 100 116 139;
--trinkui-border: 226 232 240;
--trinkui-surface: 248 250 252;
}
.dark {
--trinkui-bg: 9 9 11;
--trinkui-fg: 250 250 250;
--trinkui-primary: 129 140 248;
--trinkui-primary-fg: 255 255 255;
--trinkui-secondary: 24 24 27;
--trinkui-secondary-fg: 228 228 231;
--trinkui-accent: 251 146 60;
--trinkui-muted: 113 113 122;
--trinkui-border: 39 39 42;
--trinkui-surface: 18 18 21;
}4Use components in a route
Import trink-ui sections directly in your Remix routes. Remix renders on the server first, and animations hydrate on the client:
import {
HeroCentered,
FeaturesGrid,
FAQAccordion,
CTACentered,
FooterColumns,
} from "@trinkui/react";
export default function Index() {
return (
<main>
<HeroCentered
title="Welcome to our platform"
subtitle="The modern way to build and ship."
primaryAction={{ label: "Sign Up Free", href: "/signup" }}
secondaryAction={{ label: "Documentation", href: "/docs" }}
/>
<FeaturesGrid
title="Built for developers"
features={[
{ icon: "server", title: "Edge-Ready", description: "Deploy anywhere" },
{ icon: "lock", title: "Secure", description: "Enterprise-grade security" },
{ icon: "refresh", title: "Real-Time", description: "Instant updates" },
]}
/>
<FAQAccordion
title="Frequently asked questions"
items={[
{ question: "Is it free?", answer: "Yes, the starter plan is free forever." },
{ question: "Can I self-host?", answer: "Absolutely. Full Docker support included." },
]}
/>
<CTACentered
theme="dark"
title="Ready to ship?"
primaryAction={{ label: "Get Started", href: "/signup" }}
/>
<FooterColumns
brand={{ name: "Remix App", description: "Built with trink-ui" }}
columns={[
{ title: "Product", links: [{ label: "Features", href: "/features" }] },
{ title: "Legal", links: [{ label: "Privacy", href: "/privacy" }] },
]}
/>
</main>
);
}Server-side rendering notes
trink-ui components render static HTML on the server and hydrate animations on the client. The animation wrappers use useReducedMotion to respect user preferences. If you want to skip client-side hydration entirely for a section, pass animated={false}:
<HeroCentered
animated={false}
title="No client JS needed"
subtitle="Fully server-rendered."
primaryAction={{ label: "Learn More", href: "/docs" }}
/>