/// getting-started
Installation
PDS is a single package. Install it, import the stylesheet once, provide the two fonts, and mount the provider — five minutes to a rendered button.
1. Install the package
Add @protocore/pds with your package manager of choice. React 18 or 19 is a peer dependency; install it too if your app does not already have it.
pnpm add @protocore/pds2. Import the stylesheet
The token layer and every component’s CSS ship in one stylesheet. Import it once, as high in your app as possible — in a Next.js App Router project that is the root layout.tsx; in Vite or CRA it is your entry module.
import "@protocore/pds/styles.css";@protocore/pds/styles.css before your own global CSS so your overrides win the cascade. The stylesheet only defines --pds-* variables and .pds-* classes, so it will not collide with your app styles.3. Provide the fonts
PDS is typeset in Roboto and Roboto Mono. The token layer reads them from the CSS variables --font-roboto and --font-roboto-mono, with web-safe fallbacks if you skip this step. In Next.js, self-host both with next/font so no request leaves your origin, and expose them as those two variables on <html>:
import { Roboto, Roboto_Mono } from "next/font/google";
const roboto = Roboto({
subsets: ["latin"],
weight: ["400", "500", "700"],
variable: "--font-roboto",
display: "swap",
});
const robotoMono = Roboto_Mono({
subsets: ["latin"],
weight: ["400", "500"],
variable: "--font-roboto-mono",
display: "swap",
});
export default function RootLayout({ children }) {
return (
<html
lang="en"
className={`${roboto.variable} ${robotoMono.variable}`}
>
<body>{children}</body>
</html>
);
}Not on Next.js? Load the two families however you like (a self-hosted @font-face, a font service) and set --font-roboto / --font-roboto-mono on :root. The system never imports fonts itself.
4. Mount the provider
PdsProvider supplies the theme/accent/density context that hooks like useTheme read, and stamps the matching data-* attributes. You can either wrap your tree in it, or — the leaner option — set the attributes directly on <html> and mount the provider only where you need the context.
<html
lang="en"
data-theme="dark" // "dark" | "light"
data-accent="green" // green | blue | red | amber | violet
data-density="default" // "default" | "compact"
>The attributes on <html> are enough to theme the entire tree — every token responds to them. Reach for PdsProvider when you want to read or flip the theme at runtime from React.
import { PdsProvider } from "@protocore/pds";
<PdsProvider defaultTheme="dark" defaultAccent="green">
<App />
</PdsProvider>For persisting the choice without a flash of the wrong theme, see the no-flash snippet on the Theming page.
5. Verify
Render a Button. If it comes up as a sharp, uppercase-mono control that inverts on hover, your stylesheet, fonts, and tokens are all wired correctly.
import { Button } from "@protocore/pds";
export default function Page() {
return <Button onClick={() => alert("PDS is live")}>Deploy service</Button>;
}- [ 01 ]Install @protocore/pdsand React 18 or 19
- [ 02 ]Import styles.cssonce, at the app root
- [ 03 ]Provide the two fontsRoboto + Roboto Mono
- [ 04 ]Set data-attrs or mount PdsProvider
- [ 05 ]Render a Buttonyou're building
React support
| React | Status | Notes |
|---|---|---|
| 19.x | Supported | Recommended. Built and tested against 19. |
| 18.x | Supported | Fully supported; the peer range starts at 18.2. |
| ≤ 17 | Not supported | Relies on the modern JSX transform and hooks. |
Server components: static, render-only components (Text, Badge, Tag, Card, Table…) are server-safe. Interactive ones carry "use client" where needed and work inside client boundaries out of the box.
Mobile (React Native)
@protocore/pds-mobile is the React Native sibling of the web library — 24 core components (Button, Text, Card, Input, Field, Switch, Badge, Callout, and more) built on Pressable, View, and StyleSheet.
@protocore/pds-mobile is an early preview. The API is stable-shaped and mirrors the web components, but it has had no device-level QA yet — pin the version and expect small changes.Install the package. React and React Native are peer dependencies; an Expo or bare React Native app already has them.
npm install @protocore/pds-mobileThere is no stylesheet to import — React Native has no CSS. Instead of data-* attributes on <html>, every value comes from the theme object, so mount PdsProvider once at the root of your app and read tokens through usePdsTokens() / useTheme().
import { PdsProvider } from "@protocore/pds-mobile";
export default function App() {
return (
<PdsProvider defaultTheme="dark" defaultAccent="green">
<RootNavigator />
</PdsProvider>
);
}Components accept a style prop (a ViewStyle / TextStyle, merged after the component styles) in place of the web className, and use React Native handlers — onPress instead of onClick, onChangeText instead of onChange.
import { Card, Button, Text } from "@protocore/pds-mobile";
function DeployCard() {
return (
<Card title="Payments API" subtitle="v2.4.0">
<Text color="secondary">Handles checkout and refunds.</Text>
<Button onPress={() => deploy()}>Deploy service</Button>
</Card>
);
}next/font, so bundle the two families with your app (in Expo, useFonts from expo-font; in bare RN, link the .ttf files) under the family names the theme expects. Until they load, RN falls back to the platform system font.Per-component mobile guidance lives on each component page — use the Mobile switch in the right rail. Components without a mobile sibling show a “coming soon” note under that switch.
Charts subpath
Chart components live behind an optional subpath so that apps which never draw a chart do not pull in recharts. Install the peer and import from @protocore/pds/charts:
pnpm add rechartsimport { LineChart, ChartContainer } from "@protocore/pds/charts";recharts is a peer dependency of the charts subpath only. The core @protocore/pds entry has no chart dependency — you pay for it only if you import it.