Overview
Composable UI primitives built for real SaaS interfaces. Designed to scale from product validation to production.
Build interfaces that scale with your productLink to section
PyColors UI components are small, composable primitives built for real SaaS interfaces.
They are designed to help you build:
- dashboards
- forms
- settings pages
- billing surfaces
- admin tools
- auth flows
- data-heavy product views
This is not a UI kit for isolated demos.
It is a component foundation for products that need to evolve without becoming inconsistent.
Core idea
UI components are the lowest product layer. They should stay small, token-driven, and predictable.
Where UI fitsLink to section
PyColors is organized as a product system, not only a component library.
Design System
Tokens, colors, typography, radius, and shadows define the visual foundation.
Mental modelLink to section
Tokens define the system. Components stay small. Guides explain usage. Patterns handle complexity. Starters connect everything into a product.
This keeps the UI layer focused.
If a primitive starts carrying too much product logic, the abstraction is probably in the wrong place.
Interactive component examplesLink to section
Storybook is the canonical interactive component example system for @pycolors/ui.
Use it to inspect isolated component states, exercise keyboard and pointer behavior,
and compare the PyColors light and dark themes. These Fumadocs pages remain the
public usage documentation and product-context examples; Storybook does not replace
them.
Open PyColors UI Explorer to try the public catalog without cloning the repository. Each component page links to its exact example. To use PyColors in your own application’s Storybook, follow the consumer Storybook guide.
Contributors can also run Storybook from the repository root:
pnpm --filter @pycolors/ui storybookMaintaining examplesLink to section
Canonical examples live in packages/ui/stories/components/<family>.stories.tsx.
The public src/index.ts barrel remains the source of truth for supported families.
Foundations demonstrate existing tokens; compositions are small synthetic examples.
The local navigation orders Foundations, Components, then Compositions.
When a public component or meaningful state changes:
- Update its typed family module with an explicit
components-<family>ID, stable story exports, aDefault, a useful description and its Fumadocs link. Import through../../src/index.js, never a component's internal file. - Expose only supported args/controls. Controlled examples own their state; keep labels, native/Radix semantics, tokens and both themes intact.
- Update the matching component tests and Fumadocs page when behavior changes.
Run
pnpm --filter @pycolors/ui verify,pnpm check:ui-package, andpnpm --filter pycolors-marketing types:checkfor documentation changes. - Install Chromium with
pnpm --filter @pycolors/ui test:storybook:install, then runpnpm --filter @pycolors/ui test:storybookfor interactions, accessibility scans, light/dark and desktop/mobile checks. Check generated story IDs separately. Automated checks do not replace assistive-technology and visual review; setup, selection and diagnostics are in the story guide. - Preserve old IDs through shared-render compatibility entries when migrating
links. The migration ledger and deprecation rules live in
packages/ui/stories/README.md; the legacy module contains no new examples.
Story-only changes do not need a package release. Public API/behavior changes retain their normal Changeset, test and documentation requirements. Public stories must contain only public primitives and fixtures: no Pro source, private imports, credentials or customer data. Public Explorer hosting and a full consumer integration guide remain separate work; no production Explorer URL is assumed.
Start with the essentialsLink to section
Component categoriesLink to section
Composition rulesLink to section
Start with semantic tokensLink to section
Use token-driven utilities such as bg-card, text-muted-foreground, border-border, and shadow-sm.
Components should consume meaning, not raw visual values.
Compose before configuringLink to section
Prefer composition over large prop APIs.
If a component needs too many product-specific props, extract the product behavior into a pattern.
Keep interaction ownership clearLink to section
A primitive should usually own one interaction responsibility.
Complex flows like forms, tables, overlays, and async actions belong in Guides or Patterns.
Use UI for structure, not business logicLink to section
Components should render state clearly.
Product rules, billing checks, auth ownership, and backend decisions should stay outside the primitive layer.
When to use PatternsLink to section
Use a UI component when you need a primitive.
Use a Pattern when you need a product behavior.
| Need | Use |
|---|---|
| Button action | UI component |
| Form input | UI component |
| Form validation flow | Guide |
| Data table with loading, empty, error, filters | Pattern |
| Dropdown vs Dialog vs Sheet decision | Pattern |
| Mutation feedback with toast, retry, undo | Pattern |
Rule of thumb
Components render building blocks. Patterns explain how those blocks behave in a real product.
What to avoidLink to section
Prefer
- small primitives
- semantic tokens
- composition-first APIs
- clear accessibility defaults
- patterns for complex flows
Avoid
- hardcoded one-off styles
- giant components with too many variants
- business logic inside primitives
- using badges as buttons
- duplicating the same product flow repeatedly
Explore core componentsLink to section
Next stepsLink to section
Build the primitive once. Compose the product many times.
PyColors UI is designed to keep your components simple while your SaaS grows in complexity.