@pmgpathum/sampui
v0.1.6
Published
Production-ready UI component library for Next.js applications
Maintainers
Readme
SampUI Design System
A comprehensive, production-ready UI component library for Next.js applications, built with Subframe, React, TypeScript, and Tailwind CSS.
🚀 Features
- 50+ Pre-built Components: Accessible, customizable React components synced from Subframe
- Design Tokens: Centralized design tokens for colors, typography, spacing, shadows, and animations
- Tailwind Integration: Full Tailwind CSS support with custom configuration
- TypeScript: Complete type safety across all components and tokens
- Tree-shakeable: Optimized bundle sizes with ESM and CJS support
- Next.js Ready: Built for Next.js 14+ (supports Next.js 14, 15, and 16) with App Router support
- Server Components: Proper separation of server-safe tokens and client components
📦 Installation
Private Registry Setup
SampUI is published to a private npm registry. To install, you need to configure npm authentication:
- Set up
.npmrcin your project root:
@pmgpathum:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}- Set your NPM_TOKEN environment variable:
export NPM_TOKEN=your_npm_token_hereOr add it to your .env file (make sure .env is in .gitignore).
- Install the package:
npm install @pmgpathum/sampui
# or
yarn add @pmgpathum/sampui
# or
pnpm add @pmgpathum/sampuiRequirements
- Node.js >= 18.0.0
- npm >= 9.0.0
- React >= 18.0.0
- Next.js >= 14.0.0 (supports 14.x, 15.x, and 16.x)
- Tailwind CSS >= 3.4.0
🎯 Quick Start
1. Install Dependencies
npm install @pmgpathum/sampui2. Load Public Sans Font
SampUI components use the Public Sans font family. You need to load it in your application:
Option A: Using Next.js Font Optimization (Recommended)
// app/layout.tsx (App Router)
import { Public_Sans } from 'next/font/google';
import '@pmgpathum/sampui/styles';
const publicSans = Public_Sans({
subsets: ['latin'],
variable: '--font-public-sans',
display: 'swap',
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" className={publicSans.variable}>
<body>{children}</body>
</html>
);
}Option B: Using HTML Link Tag
Add this to your app/layout.tsx or pages/_app.tsx:
// app/layout.tsx (App Router)
import '@pmgpathum/sampui/styles';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet"
/>
</head>
<body>{children}</body>
</html>
);
}Or for Pages Router:
// pages/_app.tsx
import '@pmgpathum/sampui/styles';
import Head from 'next/head';
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet"
/>
</Head>
<Component {...pageProps} />
</>
);
}Important: Without loading Public Sans font, components will fall back to system fonts and typography weights may appear incorrect.
3. Configure Tailwind CSS
Extend your tailwind.config.js with the SampUI Tailwind configuration:
// tailwind.config.js
import sampuiConfig from '@pmgpathum/sampui/tailwind-config';
export default {
...sampuiConfig,
content: [
...sampuiConfig.content,
'./src/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
};Or using CommonJS:
// tailwind.config.js
const sampuiConfig = require('@pmgpathum/sampui/tailwind-config');
module.exports = {
...sampuiConfig,
content: [
...sampuiConfig.content,
'./src/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
};Important: The SampUI Tailwind config includes all design tokens (colors including brand colors, typography, spacing, shadows, etc.) needed for components to render correctly.
4. Use Components
Server Components (Recommended)
// app/page.tsx
import { Button, Card, TextField } from '@pmgpathum/sampui/client';
export default function HomePage() {
return (
<Card>
<TextField placeholder="Enter your name" />
<Button variant="brand-primary">Submit</Button>
</Card>
);
}Client Components
// components/MyComponent.tsx
'use client';
import { Button, Dialog, Toast } from '@pmgpathum/sampui/client';
export function MyComponent() {
return (
<>
<Button onClick={() => alert('Clicked!')}>Click me</Button>
<Dialog>...</Dialog>
</>
);
}📚 Component Usage Examples
Buttons
import { Button, IconButton, LinkButton } from '@pmgpathum/sampui/client';
// Primary button
<Button variant="brand-primary" size="large">
Primary Action
</Button>
// Button with icon
<Button
variant="brand-secondary"
icon={<Icon name="Plus" />}
iconRight={<Icon name="ArrowRight" />}
>
Add Item
</Button>
// Loading state
<Button loading={isLoading}>Submit</Button>
// Icon button
<IconButton icon={<Icon name="Settings" />} />Form Inputs
import { TextField, TextArea, Select, Checkbox, Switch } from '@pmgpathum/sampui/client';
// Text field
<TextField
label="Email Address"
placeholder="Enter your email"
helpText="We'll never share your email"
error={hasError}
icon={<Icon name="Mail" />}
/>
// Text area
<TextArea
label="Description"
placeholder="Enter description"
rows={4}
/>
// Select dropdown
<Select
label="Country"
options={[
{ value: 'us', label: 'United States' },
{ value: 'uk', label: 'United Kingdom' },
]}
/>
// Checkbox
<Checkbox label="I agree to the terms" />
// Switch
<Switch label="Enable notifications" />Feedback Components
import { Alert, Toast, Loader, Progress } from '@pmgpathum/sampui/client';
// Alert
<Alert variant="success" title="Success!">
Your changes have been saved.
</Alert>
// Toast (requires ToastProvider)
<Toast.Provider>
<Toast.Trigger>Show Toast</Toast.Trigger>
</Toast.Provider>
// Loader
<Loader size="large" />
// Progress bar
<Progress value={60} max={100} />Overlays & Modals
import { Dialog, Drawer, Tooltip, DropdownMenu } from '@pmgpathum/sampui/client';
// Dialog
<Dialog.Root>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Dialog.Content>
<Dialog.Title>Confirm Action</Dialog.Title>
<Dialog.Description>Are you sure?</Dialog.Description>
<Dialog.Footer>
<Button variant="neutral-secondary">Cancel</Button>
<Button variant="brand-primary">Confirm</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>
// Drawer
<Drawer.Root>
<Drawer.Trigger>Open Drawer</Drawer.Trigger>
<Drawer.Content>...</Drawer.Content>
</Drawer.Root>
// Tooltip
<Tooltip content="This is a tooltip">
<Button>Hover me</Button>
</Tooltip>Data Display
import { Table, Avatar, Badge, Card } from '@pmgpathum/sampui/client';
// Table
<Table.Root>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>Status</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>John Doe</Table.Cell>
<Table.Cell>
<Badge variant="success">Active</Badge>
</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Root>
// Avatar
<Avatar src="/avatar.jpg" alt="User" size="large" />
// Badge
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="destructive">Error</Badge>Navigation
import { Tabs, Breadcrumbs, Stepper } from '@pmgpathum/sampui/client';
// Tabs
<Tabs.Root defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Content 1</Tabs.Content>
<Tabs.Content value="tab2">Content 2</Tabs.Content>
</Tabs.Root>
// Breadcrumbs
<Breadcrumbs>
<Breadcrumbs.Item href="/">Home</Breadcrumbs.Item>
<Breadcrumbs.Item href="/products">Products</Breadcrumbs.Item>
<Breadcrumbs.Item>Current Page</Breadcrumbs.Item>
</Breadcrumbs>
// Stepper
<Stepper.Root currentStep={2}>
<Stepper.Step>Step 1</Stepper.Step>
<Stepper.Step>Step 2</Stepper.Step>
<Stepper.Step>Step 3</Stepper.Step>
</Stepper.Root>🎨 Theming & Customization
Design Tokens
SampUI provides a comprehensive set of design tokens that you can use directly:
import { colors, typography, spacing, shadows, tokens } from '@pmgpathum/sampui';
// Use tokens programmatically
const primaryColor = colors.primary[500];
const fontSize = typography.fontSize.lg;
const padding = spacing[4];
// Or use the unified tokens object
const { colors, typography, spacing } = tokens;Customizing Colors
Extend the color tokens in your Tailwind config:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
...require('@pmgpathum/sampui/tokens').colors,
// Add your custom colors
brand: {
primary: '#your-color',
},
},
},
},
};CSS Variables
SampUI uses CSS variables for theming. You can override them:
/* app/globals.css */
:root {
--color-primary-500: #your-color;
--spacing-4: 1.5rem;
/* ... other overrides */
}Component Variants
Most components support multiple variants:
- Buttons:
brand-primary,brand-secondary,brand-tertiary,neutral-primary,neutral-secondary,neutral-tertiary,destructive-primary,destructive-secondary,destructive-tertiary,inverse - Sizes:
large,medium,small - States:
default,hover,active,disabled,loading
🎯 Design Token Reference
Colors
import { colors } from '@pmgpathum/sampui';
// Primary colors
colors.primary[50] // Lightest
colors.primary[500] // Base
colors.primary[900] // Darkest
// Semantic colors
colors.success[500]
colors.warning[500]
colors.destructive[500]
colors.neutral[500]Typography
import { typography } from '@pmgpathum/sampui';
typography.fontFamily.sans
typography.fontSize.xs // 12px
typography.fontSize.sm // 14px
typography.fontSize.base // 16px
typography.fontSize.lg // 18px
typography.fontSize.xl // 20px
typography.fontWeight.normal
typography.fontWeight.medium
typography.fontWeight.semibold
typography.fontWeight.boldSpacing
import { spacing } from '@pmgpathum/sampui';
spacing[0] // 0px
spacing[1] // 4px
spacing[2] // 8px
spacing[4] // 16px
spacing[8] // 32px
spacing[16] // 64pxShadows
import { shadows } from '@pmgpathum/sampui';
shadows.sm
shadows.md
shadows.lg
shadows.xlBreakpoints
import { breakpoints } from '@pmgpathum/sampui';
breakpoints.sm // 640px
breakpoints.md // 768px
breakpoints.lg // 1024px
breakpoints.xl // 1280px
breakpoints['2xl'] // 1536px📘 TypeScript Usage
SampUI is built with TypeScript and provides full type safety:
import { Button } from '@pmgpathum/sampui/client';
import type { ButtonProps } from '@pmgpathum/sampui/client';
// Type-safe props
const buttonProps: ButtonProps = {
variant: 'brand-primary', // Autocomplete works!
size: 'large',
disabled: false,
};
<Button {...buttonProps} />Type Definitions
All component props are exported with TypeScript types:
import type {
ButtonProps,
TextFieldProps,
DialogProps,
// ... all component types
} from '@pmgpathum/sampui/client';⚡ Next.js App Router Integration
SampUI is optimized for Next.js App Router with proper server/client component separation:
Server Components
Use tokens and utilities in Server Components:
// app/page.tsx (Server Component)
import { colors, spacing } from '@pmgpathum/sampui';
export default function ServerPage() {
return (
<div style={{ color: colors.primary[500] }}>
Server Component
</div>
);
}Client Components
Import components from @pmgpathum/sampui/client:
// components/ClientComponent.tsx
'use client';
import { Button, Dialog } from '@pmgpathum/sampui/client';
export function ClientComponent() {
return <Button>Click me</Button>;
}Layout Integration
// app/layout.tsx
import '@pmgpathum/sampui/styles';
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
{children}
</body>
</html>
);
}Route Groups
// app/(marketing)/layout.tsx
import { DefaultPageLayout } from '@pmgpathum/sampui/client';
export default function MarketingLayout({ children }) {
return <DefaultPageLayout>{children}</DefaultPageLayout>;
}🔧 Troubleshooting
Styles Not Loading
Problem: Components render but styles are missing.
Solution:
- Ensure you've imported the styles:
import '@pmgpathum/sampui/styles'; - Check that Tailwind is configured correctly
- Verify the content paths in
tailwind.config.jsinclude the package:content: [ './node_modules/@pmgpathum/sampui/dist/**/*.{js,mjs}', ]
"use client" Directive Errors
Problem: Error about missing 'use client' directive.
Solution:
- Import components from
@pmgpathum/sampui/clientinstead of@pmgpathum/sampui - Or add
'use client';at the top of your component file
TypeScript Errors
Problem: Type errors when importing components.
Solution:
- Ensure TypeScript version >= 5.3.0
- Check
tsconfig.jsonincludes the package:{ "compilerOptions": { "moduleResolution": "bundler", "resolveJsonModule": true } }
Build Errors
Problem: Build fails with module resolution errors.
Solution:
- Clear
.nextcache:rm -rf .next - Reinstall dependencies:
rm -rf node_modules && npm install - Ensure Node.js version >= 18.0.0
Private Registry Authentication
Problem: Cannot install package from private registry.
Solution:
- Verify
.npmrcis configured correctly - Check
NPM_TOKENenvironment variable is set - Ensure token has access to
@sampathscope - Try:
npm config get @sampath:registry
Component Not Rendering
Problem: Component imports but doesn't render.
Solution:
- Check browser console for errors
- Verify styles are imported
- Ensure component is used in a Client Component
- Check component props are correct (use TypeScript for validation)
Tailwind Classes Not Working
Problem: Custom Tailwind classes don't apply.
Solution:
- Verify content paths in
tailwind.config.js - Restart your dev server after config changes
- Check for CSS conflicts or specificity issues
📖 Additional Resources
🛠️ Development
See CONTRIBUTING.md for development setup and guidelines.
📝 Versioning
This project uses Changesets for version management.
📄 License
UNLICENSED - Private package for Sampath Bank use only.
🆘 Support
For issues and support, please contact the design system team or open an issue in the internal repository.
