The Coline design system: accessible React components for Coline Apps, themed live by the host workspace, and for Coline Sites in light and dark. Tailwind v4 stylesheet included. MIT.
The Coline design system for tier-2 (React) Coline Apps — the same components the Coline platform itself uses, themed live by the host workspace. Your app automatically matches the user's theme, including dark mode and brand accents, with no theme code of your own.
import {
Button,
Card,
ColineAppProvider,
Input,
useColine,
useColineQuery,
} from "@colineapp/ui";
import "@colineapp/ui/styles.css";
function NotesList() {
const coline = useColine();
const notes = useColineQuery(
(c) => c.files.list({ typeKey: "notes.note" }),
[],
);
return (
<Card>
{notes.data?.files.map((file) => (
<Button key={file.fileId} variant="ghost">
{file.name}
</Button>
))}
</Card>
);
}
export default function App() {
return (
<ColineAppProvider>
<NotesList />
</ColineAppProvider>
);
}
ColineAppProvider — connects the sandbox bridge and provides context.useColine (the capability API), useColineContext (workspace /
surface / file context), useColineQuery (data fetching with
loading/error state), useColorScheme.styles.css — the compiled stylesheet; theme tokens are overridden at
runtime by the host, so one CSS file serves every workspace theme.Used inside a Coline App's react-tier surface ({ tier: "react", entry: "main.tsx" } in the manifest). Scaffold a working app with
npx create-coline-app my-app.
Full guides at coline.app/developers/docs.
MIT © Coline
Run coline-app check before pushing: it checks types, the manifest, hosted logic,
and the React bundle without uploading. dev --internal updates one development
version; install it in the workspace and reload after changes. The CLI bundles
from the app's installed dependencies and preserves imported CSS and inline assets.
App-specific Tailwind v4 utilities compile automatically with CLI 2.5. Import
@colineapp/ui/styles.css and then ./app.css; use complete class names.
The starter includes a React home and editor, tree mobile fallback, and a tool.
Use coline.tools.invoke or actions.invokeTool to run the same declared tool
from UI that Kairo runs. Save with to detect concurrent edits.
Homes/editors can write within grants; previews and server render handlers cannot.
tests the interactive contract and
simulates revoked consent.
expectedVersioncreateTestWorkspace(app).client()grantedPermissionsNew tasks, calendar, messages, and references capabilities require their
explicit manifest permissions and retain the invoking user's workspace access.
Use files.list({ scope: "workspace" }) for shared files; document writes stay
with the owning app. Collections are install-private. Code integration and a
native mobile React runtime are separate work.
useLiveCollection<RecordType>("collection", { where, orderBy, limit }) returns
records, pending, status, error, nextCursor, insert, update, delete,
setAccess, and refresh. Inline query objects are supported. Mutations update
local UI immediately and reject on conflicts or permission failures; catch their
promises to present the error. The hook owns subscription cleanup and reconnect
recovery. Use filtered/paged views (at most 200 records), not an entire workspace
in one hook. Structured-record sync does not imply CRDT text editing or offline
write persistence.
Use AppPage and PageToolbar for consistent hierarchy, RecordTable with
SplitView/DetailPanel for queues, Board/BoardColumn/BoardCard for stages,
and SettingsSection for configuration. EmptyState, AppErrorState,
AppLoadingState, and StatusBadge cover common states. Their CSS ships in
@colineapp/ui/styles.css; they require no app-side utility generation.
Patterns compose around your domain and capabilities. They do not supply data,
routing, drag-and-drop, or persistence. RecordTable provides a first-cell button
when onOpen is set (don't nest a second control there); secondary columns hide
at narrow widths. Split details stack on mobile; the app owns focus management.
See the scaffold's examples/ for complete interactive references.
Tabs uses the same raised selection as Coline and Upstream. Selection springs
and content transitions are automatic; no indicator or animation wrapper is
required. Each tabs group owns its indicator so multiple groups never collide.
TabsIndicator remains available for existing custom compositions.
<Tabs defaultValue="inbox">
<TabsList aria-label="Views">
<TabsTrigger value="inbox">Inbox</TabsTrigger>
<TabsTrigger value="roadmap">Roadmap</TabsTrigger>
</TabsList>
<TabsContent value="inbox">{/* Inbox */}</TabsContent>
<TabsContent value="roadmap">{/* Roadmap */}</TabsContent>
</Tabs>
<FilterMenu
aria-label="Filter by status"
value={status}
onValueChange={setStatus}
options={[{ value: "all", label: "All statuses" }, { value: "planned", label: "Planned" }]}
/>
FilterMenu composes the exact Coline DropdownMenu radio group, surface, and
sliding highlight. Use DropdownMenu directly for action menus. PageToolbar
is borderless. RecordTable uses separated, rounded selection/hover rows.
Dialogs and menus include their animation CSS; the provider respects reduced
motion, including portals. Buttons default to type="button"; use
type="submit" for a form's submit action.
Use component defaults rather than copying their CSS into the app. Custom CSS
variables scoped to AppPage do not reach portalled dialogs/menus. Keep decorative
app variables at :root when they must cross portals, and retain host theme tokens.
App bundles include their dependencies: upgrade, rebuild and push to adopt a UI
release. Updating npm does not rewrite already-published app bundles.