get started

Install

Three packages — tokens, design, icons — publish to GitHub Packages under @8maverik8. Wire your registry once, then install across all your Twenty extensions and standalone Next.js apps. For front-component code add twenty-sdk too — it unlocks the /twenty-ui bridge subpath (see Step 3).

1

Configure GitHub Packages

The packages publish to npm.pkg.github.com under the @8maverik8 scope. Add an .npmrc at the root of your project:

.npmrcbash
@8maverik8:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}
Token scope
GITHUB_PACKAGES_TOKEN is a fine-grained Personal Access Token with the read:packages scope. For CI, set it as a secret on the workflow and inject as an env var. Never commit the raw token to .npmrc.
2

Install the three packages

Each one is small and depends only on tokens (no transitive Twenty SDK). Install all three at once:

bash
pnpm add @8maverik8/twenty-tokens \
@8maverik8/twenty-design \
@8maverik8/twenty-icons
What you get@8maverik8/twenty-tokens — TypeScript dictionary + CSS files exporting all --t-* variables and component interactive states.@8maverik8/twenty-design — the React components (Button, Input, Modal, DataTable, …).@8maverik8/twenty-icons — Tabler-icon re-export plus a typed TwentyIconName literal union for autocomplete on metadata fields.
3

Use inside a Twenty front-component

Twenty's front-component host renders inside a sandboxed Remote DOM bridge. The bridge strips all data-* attributes except data-testid, which breaks our Radix-based primitives (Button, Tag, Modal, Tooltip, etc — they use [data-state]/[data-variant] selectors). Use two import paths:

  • @8maverik8/twenty-design/twenty-ui — re-exports twenty-sdk/ui (Twenty's own DS, verified inside front-component'ы) for the ~19 overlapping primitives.
  • @8maverik8/twenty-design — pull our recipes (PanelHeader, LineItemCard, TotalsBlock, etc — pure inline-styles + useState, no Radix).
terminalbash
pnpm add twenty-sdk twenty-client-sdk
# (already a dep of any Twenty extension app)
src/components/deal-form.front-component.tsxtsx
import { defineFrontComponent } from 'twenty-sdk/define';
import { useRecordId } from 'twenty-sdk/front-component';
// Overlapping primitives — Twenty's own, via the bridge:
import { Button, ThemeProvider } from '@8maverik8/twenty-design/twenty-ui';
// Recipes — our own, work in Remote DOM out of the box:
import { PanelHeader } from '@8maverik8/twenty-design';
import { IconReceipt } from '@8maverik8/twenty-icons';
const DealForm = () => {
const recordId = useRecordId();
return (
<ThemeProvider colorScheme="light">
<PanelHeader
title="New deal"
actions={
<Button title="Save" accent="blue" Icon={IconReceipt} onClick={() => save(recordId)} />
}
/>
{/* …rest of the form composed from twenty-sdk/ui primitives */}
</ThemeProvider>
);
};
export default defineFrontComponent({
universalIdentifier: 'a1b2c3d4-...',
name: 'deal-form',
description: 'New deal entry',
component: DealForm,
});
Remote DOM constraint, in plain English
Bridge whitelist (from HTML_COMMON_PROPERTIES_CONFIG in twenty-front-component-renderer): id, className, style, title, tabIndex, role, aria-label, aria-hidden, data-testid — everything else is stripped. CSS-class-based styling works because className survives; data-state/data-variantattribute selectors don't. Don't fight it — use the bridge + recipes.
4

Use in a standalone Next.js / Vite app

Outside Twenty you need to do two extra things: import the theme CSS, and wrap your tree in the providers used by Tooltip and Toast.

app/layout.tsxtsx
import type { ReactNode } from 'react';
import { TooltipProvider, ToastProvider } from '@8maverik8/twenty-design';
// One import loads both the light + dark theme variables and the
// interactive component states (hover, focus-visible, active, ...).
import '@8maverik8/twenty-tokens/themes';
import '@8maverik8/twenty-tokens/components';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en" className="light" style={{ colorScheme: 'light' }}>
<body>
<TooltipProvider>
<ToastProvider>
{children}
</ToastProvider>
</TooltipProvider>
</body>
</html>
);
}
Switching themes
Toggle the .light or .dark class on the <html> element (and update color-scheme). Every --t-* variable, including the syntax-highlight palette inside CodeBlock, switches automatically.
5

Verify the install

Render any component to confirm the chain is wired:

tsx
import { Button } from '@8maverik8/twenty-design';
export const Hello = () => (
<Button variant="primary" accent="blue">It works</Button>
);
Hover the button — the background should shift to --t-color-blue10. Tab into it — a 3 px ring of --t-accent-tertiary should appear. If both happen, you're set.

License

All three packages publish under AGPL-3.0-only, consistent with twenty-sdk. Source lives at github.com/8Maverik8/twenty-platform .