@projectdiscoveryio/pd-design-system
v0.0.3
Published
A modern design system built with React, TypeScript, Tailwind CSS, shadcn/ui, and Radix UI
Readme
PD Design System
A modern, production-ready design system built with React, TypeScript, Tailwind CSS, shadcn/ui, and Radix UI primitives.
🚀 Features
- ✅ React 18 & 19 with TypeScript
- ✅ Tailwind CSS for styling
- ✅ TypeScript-based Design Tokens with auto-generated CSS
- ✅ shadcn/ui components (customizable)
- ✅ Radix UI primitives for accessibility
- ✅ Storybook 8 for component documentation
- ✅ Tree-shakeable ESM/CJS builds
- ✅ Type-safe with full TypeScript support
- ✅ Dark mode support built-in
- ✅ CVA (Class Variance Authority) for component variants
📦 Installation
From npm (Recommended)
npm install @projectdiscovery/pd-design-system
# or
yarn add @projectdiscovery/pd-design-system
# or
pnpm add @projectdiscovery/pd-design-systemLocal Development / Git
# From local directory
npm install file:../path/to/pd-design-system
# From GitHub
npm install git+https://github.com/projectdiscovery/pd-design-system.gitSetup Tailwind CSS
Since this design system uses Tailwind CSS, you need to configure it in your consuming application:
1. Install Tailwind CSS (if not already installed):
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p2. Update your tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
// 🔥 IMPORTANT: Include design system components
"./node_modules/@projectdiscovery/pd-design-system/dist/**/*.{js,mjs}",
],
darkMode: "class", // 🔥 REQUIRED for theme switching
theme: {
extend: {},
},
plugins: [],
};3. Import the design system styles in your main CSS/entry file:
/* app/globals.css or src/index.css */
@import "@projectdiscovery/pd-design-system/styles.css";Or import in your main TypeScript/JavaScript file:
// main.tsx or App.tsx
import "@projectdiscovery/pd-design-system/styles.css";🎨 Usage
Step 1: Wrap with ThemeProvider (REQUIRED)
// app/layout.tsx or App.tsx
import { ThemeProvider } from "@projectdiscovery/pd-design-system";
import "@projectdiscovery/pd-design-system/styles.css";
export default function App() {
return (
<ThemeProvider>
<YourApp />
</ThemeProvider>
);
}Step 2: Use Components with Type-Safe Colors
import {
Button,
Card,
CardHeader,
CardTitle,
CardContent,
Input,
} from "@projectdiscovery/pd-design-system";
function MyComponent() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent>
<Input placeholder="Enter your name" />
{/* Use built-in variants */}
<Button variant="default">Submit</Button>
{/* Or use custom colors from theme (with autocomplete!) */}
<Button bgColor="green">Success</Button>
<Button bgColor="colors.blue.600">Custom Blue</Button>
</CardContent>
</Card>
);
}Button Usage
import { Button } from "@projectdiscovery/pd-design-system";
{/* Built-in variants */}
<Button variant="default">Default</Button>
<Button variant="destructive">Delete</Button>
<Button variant="success">Success</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
{/* Custom colors from theme (TypeScript autocomplete!) */}
<Button bgColor="green">Green Button</Button>
<Button bgColor="red">Red Button</Button>
<Button bgColor="colors.blue.700">Deep Blue</Button>
{/* Sizes */}
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
{/* ❌ className is NOT available (design system controls styling) */}
<Button className="custom">Won't work</Button>Card Component
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
Button,
} from "@projectdiscovery/pd-design-system";
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card description goes here</CardDescription>
</CardHeader>
<CardContent>
<p>Card content</p>
</CardContent>
<CardFooter>
<Button>Action</Button>
</CardFooter>
</Card>;Input Component
import { Input } from "@projectdiscovery/pd-design-system";
<Input type="email" placeholder="Enter email" />
<Input type="password" placeholder="Password" disabled />🎨 Design Tokens
This design system uses TypeScript-based design tokens with automatic CSS generation. All colors and semantic tokens are defined in TypeScript for type safety and maintainability.
Working with Tokens
# Generate CSS from TypeScript tokens
npm run generate-tokens
# Tokens are auto-generated before build
npm run buildKey files:
src/lib/tokens/primitives.ts- Color scales (100-950)src/lib/tokens/semantic.ts- Semantic tokens (border, content, background)src/styles/globals.css- Auto-generated CSS variables (don't edit directly!)
📖 Documentation:
- THEME_USAGE.md - 📖 How to use theme object (START HERE!)
- TOKENS.md - Token usage guide
- TOKEN_WORKFLOW.md - How to update tokens
- src/lib/tokens/README.md - Technical details
Using Tokens
With Theme Object (Recommended for dynamic styling):
import { theme } from "@projectdiscovery/pd-design-system";
// Full TypeScript autocomplete!
<div
style={{
backgroundColor: theme.background.primary,
color: theme.content.primary,
border: `1px solid ${theme.border.blue}`,
}}
/>;
// Access any token with autocomplete
const brandColor = theme.colors.blue[600]; // "#004BFF"With Tailwind Classes (Recommended for static styling):
<div className="bg-background-primary text-content-primary border-border-blue" />Direct Token Access:
import { blue, borderTokens } from "@projectdiscovery/pd-design-system";
const color = blue[500]; // "#3772FF"
const borderColor = borderTokens.light.primary;🛠️ Development
Prerequisites
- Node.js 18+
- npm/yarn/pnpm
Setup
# Install dependencies
npm install
# Generate CSS tokens from TypeScript
npm run generate-tokens
# Start Storybook (component development & documentation)
npm run storybook
# Build the library (auto-generates tokens first)
npm run build
# Type check
npm run type-check
# Lint
npm run lint📚 Storybook
Run Storybook to see all components with interactive examples:
npm run storybookThis will start Storybook at http://localhost:6006
🎨 Custom Storybook Theme
Our Storybook is styled with PD Design System! The entire Storybook UI uses:
- Custom theme matching your design tokens
- Welcome page built with PD components
- Dark mode support
- Branded documentation
See STORYBOOK.md for customization details.
🏗️ Project Structure
pd-ds/
├── src/
│ ├── components/
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.stories.tsx
│ │ │ └── index.ts
│ │ ├── Card/
│ │ ├── Input/
│ │ └── ...
│ ├── lib/
│ │ ├── tokens/ # 🎨 TypeScript design tokens
│ │ │ ├── primitives.ts # Color scales
│ │ │ ├── semantic.ts # Semantic tokens
│ │ │ ├── generate-css.ts
│ │ │ ├── types.ts
│ │ │ └── index.ts
│ │ └── utils.ts # Utility functions (cn, etc.)
│ ├── styles/
│ │ └── globals.css # ⚠️ Auto-generated CSS variables
│ └── index.ts # Main export file
├── scripts/
│ └── generate-css-tokens.ts # CSS generation script
├── .storybook/ # Storybook configuration
├── components.json # shadcn/ui configuration
├── tailwind.config.js # Tailwind configuration (uses TS tokens)
├── tsconfig.json # TypeScript configuration
├── tsup.config.ts # Build configuration
└── package.json🎨 Adding shadcn/ui Components
To add more shadcn/ui components to this design system:
npx shadcn@latest add [component-name]Example:
npx shadcn@latest add dialog
npx shadcn@latest add dropdown-menu
npx shadcn@latest add selectThe components will be added to src/components/ and you can customize them as needed.
🌗 Dark Mode
The design system has built-in dark mode support. To enable dark mode in your app:
// Add the 'dark' class to your root element
<html className="dark">{/* Your app */}</html>Or toggle it dynamically:
function ThemeToggle() {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
if (isDark) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, [isDark]);
return <button onClick={() => setIsDark(!isDark)}>Toggle Theme</button>;
}📝 Customization
Using the cn utility
All components use the cn utility for className merging:
import { Button, cn } from "@projectdiscovery/pd-design-system";
<Button className={cn("my-custom-class", someCondition && "conditional-class")}>
Click me
</Button>;Extending Components
You can extend components by wrapping them:
import { Button, type ButtonProps } from "@projectdiscovery/pd-design-system";
interface MyButtonProps extends ButtonProps {
isLoading?: boolean;
}
export function MyButton({ isLoading, children, ...props }: MyButtonProps) {
return (
<Button {...props} disabled={isLoading || props.disabled}>
{isLoading ? "Loading..." : children}
</Button>
);
}📦 Publishing
To npm:
# 1. Build the library
npm run build
# 2. Update version
npm version patch|minor|major
# 3. Publish
npm publishTo private registry:
Update package.json:
{
"publishConfig": {
"registry": "https://your-private-registry.com"
}
}🤝 Contributing
- Add new components to
src/components/[ComponentName]/ - Include TypeScript types
- Write Storybook stories
- Export from
src/index.ts - Update this README
📄 License
MIT
🔗 Links
Built with ❤️ using React, TypeScript, and Tailwind CSS
