Installation

Install, wrap, and control every token.

Add three packages, import the styles once, and wrap your app in the provider. Then tune the whole system - palette, radius, typography, dark mode, direction - from one layer of CSS variables.

Requirements

dev-dga targets modern React and any bundler that can import a CSS file.

React 19

react and react-dom 19 are peer dependencies - the components use the React 19 runtime.

A CSS-aware bundler

Next.js, Vite, Remix - any setup where you can import a stylesheet. No CSS-in-JS runtime is involved.

TypeScript (optional)

Full types ship with the package. TypeScript is recommended but not required.

Install the packages

Three packages: the React components, the compiled CSS, and the design tokens. Install all three together.

npm i @dev-dga/react @dev-dga/css @dev-dga/tokens

The CSS package is a peer dependency of the React package - install it explicitly, not transitively.

Import the styles once

Import the stylesheet a single time at the root of your app (e.g. your root layout or entry file). It ships the reset, tokens, dark theme, and every component style.

// app/layout.tsx (Next.js) or your entry fileimport '@dev-dga/css';

Because the design system lives in @layer ddga-base / ddga-components, any unlayered rule of yours overrides it without !important.

Style with or without Tailwind

@dev-dga/css is plain CSS in two cascade layers, ddga-base and ddga-components. Tailwind is optional. Use component props for a component’s internals, and utilities or your own CSS for the layout around them. Restyling a component’s internals with utility classes is brittle: cascade-layer order, not specificity, decides which rule wins.

Both Tailwind majors get the DGA scale as utilities through a token bridge: bg-primary, text-ink, text-ink-secondary, rounded-lg, shadow-md, text-display-md, max-w-dga, and every palette step (bg-sa-600, border-gray-200). Every value is a var(--ddga-*) reference, so DgaProvider themes and dark mode flow through the utilities.

No Tailwind

Import the stylesheet once and compose the components. Style the layout around them with your own CSS.

import '@dev-dga/css';import { DgaProvider, Button } from '@dev-dga/react';

Tailwind v3

Install @dev-dga/tokens so the preset import is explicit:

npm install @dev-dga/tokens

Add the preset to your Tailwind config:

// tailwind.config.jsimport { dgaPreset } from '@dev-dga/tokens/tailwind-preset';export default { presets: [dgaPreset], content: ['./src/**/*.{ts,tsx}'] };

Layer the stylesheets in this order:

/* app.css */@layer tailwind-base, ddga-base, ddga-components, tailwind-utilities;@import '@dev-dga/css';@layer tailwind-base {  @tailwind base;}@layer tailwind-utilities {  @tailwind components;  @tailwind utilities;}

The order statement must come first, and the @layer tailwind-base wrap is mandatory. An unlayered @tailwind base (preflight sets border-width: 0 on every element) beats every layered rule and strips the border from every component. The library declares its own two layers at the top of its stylesheet, so an order statement placed after the import sorts tailwind-base above the components.

Opacity modifiers on bridge colors (bg-primary/50) need v4. Tailwind v3 skips them for var() values.

Tailwind v4

No config file and no @source needed. Preflight is skipped; the library reset covers it.

/* app.css */@layer theme, base, ddga-base, ddga-components, components, utilities;@import 'tailwindcss/theme.css' layer(theme);@import 'tailwindcss/utilities.css' layer(utilities);@import '@dev-dga/css';@import '@dev-dga/css/tailwind.css';

To add preflight, import it into the base layer. The order statement keeps base below ddga-base:

@import 'tailwindcss/preflight.css' layer(base);

The bridge keeps Tailwind’s own palette and scales. To keep only the DGA tokens (strict mode), reset the namespaces before the bridge import, not after it:

@import '@dev-dga/css';@theme inline {  --color-*: initial;  --color-white: #fff;}@import '@dev-dga/css/tailwind.css';

Rules for both majors

  • Props style a component’s internals. Utilities and your own CSS style the layout around it.
  • cn() in @dev-dga/react is clsx only. For stacked conflicting utilities on your own elements, use tailwind-merge on your side.
  • dark: follows [data-theme="dark"] from DgaProvider, not the OS preference.
  • Tailwind v3: the @layer order statement must come before @import '@dev-dga/css', and @tailwind base must sit inside @layer tailwind-base. An unlayered preflight strips every component border.
  • Tailwind v4 strict mode (--color-*: initial) must come before the bridge import.
  • Tailwind v3 skips opacity modifiers such as bg-primary/50 on var() colors.
  • The bridge overrides some Tailwind defaults on purpose: rounded-lg is 16px and rounded-xl is 24px, shadow-* is the DGA navy scale, gray-* is the DGA gray ramp, text-xs to text-xl carry the DGA line-heights, and max-w-xs to max-w-6xl are the DGA widths.
  • Spacing and breakpoints equal Tailwind’s defaults, so the bridge maps neither.

Live: utilities follow the theme

This card is bridge utilities only: no library component and no custom CSS. Switch dark mode or the brand palette and every utility re-tones, because each one resolves a --ddga-* variable.

Bridge demo
Utilities onlylight mode

Commercial registration

Register a new establishment, update its activities, or renew its record. The service completes in one session and issues the certificate as a PDF.

Fee
SAR 200
Duration
3 working days
Channel
Online

Source

<article className="bg-card text-ink border border-border rounded-lg shadow-md p-6 max-w-paragraph">  <div className="flex flex-wrap items-center gap-2">    <span className="bg-primary text-primary-foreground rounded-full px-3 py-1 text-xs font-medium">      Utilities only    </span>    <span className="text-ink-tertiary text-xs dark:hidden">light mode</span>    <span className="text-ink-tertiary text-xs hidden dark:inline">dark: active</span>  </div>  <h3 className="text-display-sm font-semibold mt-5">Commercial registration</h3>  <p className="text-ink-secondary mt-2">    Register a new establishment, update its activities, or renew its record.  </p>  <dl className="grid grid-cols-1 sm:grid-cols-3 gap-3 mt-5">    <div className="bg-muted rounded-md p-3">      <dt className="text-ink-tertiary text-2xs">Fee</dt>      <dd className="text-ink text-sm font-medium">SAR 200</dd>    </div>    <div className="bg-muted rounded-md p-3">      <dt className="text-ink-tertiary text-2xs">Duration</dt>      <dd className="text-ink text-sm font-medium">3 working days</dd>    </div>    <div className="bg-muted rounded-md p-3">      <dt className="text-ink-tertiary text-2xs">Channel</dt>      <dd className="text-ink text-sm font-medium">Online</dd>    </div>  </dl>  <div className="border-t border-border mt-5 pt-4">    <a      href="#"      className="text-primary hover:text-primary-hover text-sm font-medium underline-offset-4 hover:underline"    >      Start the service    </a>  </div></article>

Wrap your app in the provider

DgaProvider supplies direction, dark mode, the brand theme, and the portal root that overlays (modals, tooltips, toasts) render into. Mount it once, near the root, above everything that uses the library.

import { DgaProvider } from '@dev-dga/react';import '@dev-dga/css';export default function App({ children }) {  return (    <DgaProvider dir="rtl" mode="light" theme={{ primary: 'saGreen' }}>      {children}    </DgaProvider>  );}

DgaProvider props

PropTypeDefaultWhat it controls
dir'ltr' | 'rtl''ltr'Layout direction. Mirrors the whole tree via logical properties.
mode'light' | 'dark''light'Color mode. Applies the dark token set on the provider root.
themeDgaThemesaGreenBrand theme - a palette name, a CSS color, or a full triplet.
localestring-BCP-47 locale forwarded to date- and number-aware components.
asElementType'div'The element the provider renders as (e.g. render on <body>).

Theme the primary palette

The whole system re-tones from one value. Pass theme.primary in any of three forms - hover and active states are derived automatically with color-mix().

  1. A built-in palette name

    One of saGreen, info, success, warning, error, gray.

  2. Any CSS color

    A hex, rgb, or oklch string. Hover and active are derived for you.

  3. An explicit triplet

    Full control via { base, hover, active, foreground } when you need exact values.

// 1 - a built-in palette name<DgaProvider theme={{ primary: 'info' }}>…</DgaProvider><DgaProvider theme={{ primary: '#7C3AED' }}>…</DgaProvider><DgaProvider  theme={{    primary: {      base: '#1B8354',      hover: '#166A45',      active: '#104631',      foreground: '#FFFFFF',    },  }}></DgaProvider>

Override any design token

Every color, radius, space, font, and shadow is a --ddga-* CSS variable declared in @layer ddga-base. Redeclare one anywhere - globally on :root, or scoped to a subtree - and the system follows. No build step, no Sass.

Token groups

GroupExample variablesControls
Color--ddga-color-primary · --ddga-color-background · --ddga-text-primary · --ddga-color-borderSurfaces, text, borders, and semantic colors.
Radius--ddga-radius-sm · --ddga-radius-md · --ddga-radius-lg · --ddga-radius-fullCorner rounding across every component.
Spacing--ddga-space-1 … --ddga-space-16The spacing scale used for padding and gaps.
Typography--ddga-font-ar · --ddga-font-mono · --ddga-font-size-* · --ddga-font-weight-*Font families, sizes, and weights.
Shadow--ddga-shadow-xs … --ddga-shadow-3xlElevation for cards, overlays, and popovers.
Charts--ddga-chart-1 … --ddga-chart-6The categorical palette for data visualization.
/* your globals.css - imported AFTER '@dev-dga/css' */:root {  --ddga-radius-md: 4px;          /* squarer corners, system-wide */  --ddga-color-primary: #0f766e;  /* teal brand */  --ddga-font-ar: 'Cairo', sans-serif;}.compact {  --ddga-card-padding: var(--ddga-space-3);  --ddga-radius-lg: 6px;}

Scope overrides to a subtree by setting the variables on any wrapper element - the cascade does the rest, in light and dark.

Theme builder

A quick taste - tweak a few tokens and watch the preview re-tone. For complete control over all 188 tokens, open the full Theme Studio.

Live preview

Account settings

Manage how your profile appears across every government service.

New
ApprovedNewMore

Your changes are saved automatically.

Quick controls

This is a preview. The Theme Studio gives you every --ddga-* token - all the color scales, radius, spacing, typography, and shadows - with live search and one-click export.

Open the full Theme Studio

Your overrides

Paste these into a CSS file loaded after @dev-dga/css (e.g. your globals.css). They override the tokens every component reads - put them on :root for the whole app, or on any element to theme a subtree. Only the values you change appear here.

globals.css
@import '@dev-dga/css'; /* the DGA design system (index.css) - load it first */:root {  /* Adjust any control below to generate token overrides */}

Dark mode

Dark mode is a curated token set, not a mechanical inversion. Drive it with the provider’s mode prop, or by toggling data-theme="dark" on a wrapper. Apply it before first paint (as this site does) to avoid a flash.

// Controlled by the provider<DgaProvider mode="dark">…</DgaProvider><div data-theme="dark"></div>

RTL & Arabic

Set dir="rtl" and the entire layout mirrors through logical properties - no per-component work. IBM Plex Sans Arabic covers Arabic and Latin from one family, so mixed content stays consistent.

<DgaProvider dir="rtl" locale="ar"></DgaProvider>

Next steps

You’re set up. Here’s where to go from here: