@opensite/ui
v0.3.3
Published
Foundational UI component library for OpenSite Semantic Site Builder with tree-shakable exports and abstract styling
Downloads
4,031
Maintainers
Readme

@opensite/ui
Foundational UI component library for the OpenSite Semantic Site Builder ecosystem. Provides tree-shakable, performance-optimized components with abstract styling support.
Features
- 🎨 Abstract Styling: Components use CSS variables for full theme customization
- 📦 Tree-Shakable: Granular imports for optimal bundle sizes
- ⚡ Performance First: Optimized for Core Web Vitals (LCP ≤2.5s, INP ≤200ms, CLS ≤0.1)
- 🎯 TypeScript: Full type safety with strict mode
- 🧩 shadcn/ui Compatible: Built on shadcn/ui foundations with Tailwind CSS v4
- 🔧 Flexible: Support for both default Tailwind styles and custom semantic builder styles
Installation
pnpm add @opensite/ui
# or
npm install @opensite/uiPeer Dependencies
This library requires React 16.8.0 or higher:
pnpm add react react-domUsage
Tree-Shakable Imports (Recommended)
For optimal bundle sizes, import components individually:
// Import specific components
import { Container } from "@opensite/ui/components/container";
import { Section } from "@opensite/ui/components/section";
// Or import multiple from grouped export
import { Container, Section, Button } from "@opensite/ui/components";Full Import (Not Recommended)
// Import all (larger bundle)
import * as UI from "@opensite/ui";Components
Container
Layout container for consistent content width and centering.
import { Container } from "@opensite/ui/components/container";
<Container maxWidth="xl">
<h1>Page Content</h1>
</Container>Props:
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "4xl" | "full"- Maximum width (default: "xl")as?: keyof JSX.IntrinsicElements- HTML element to render (default: "div")className?: string- Additional CSS classes- All standard HTML attributes
Section
Section wrapper with optional title, subtitle, and background variants.
import { Section } from "@opensite/ui/components/section";
<Section
id="features"
title="Our Features"
subtitle="What we offer"
background="gradient"
spacing="lg"
>
<p>Section content here</p>
</Section>Props:
id?: string- Section ID for anchor linkstitle?: string- Section title (renders as h2)subtitle?: string- Section subtitle/eyebrowbackground?: "white" | "gray" | "dark" | "gradient" | "primary" | "secondary" | "muted"(default: "white")spacing?: "sm" | "md" | "lg" | "xl"(default: "lg")className?: string- Additional CSS classes- All standard HTML attributes
AnimatedDialog
Animated modal dialog component using framer-motion with polished default styles.
import { AnimatedDialog } from "@opensite/ui/components/animated-dialog";
import { useState } from "react";
function MyComponent() {
const [open, setOpen] = useState(false);
return (
<AnimatedDialog
open={open}
onOpenChange={setOpen}
title="Welcome"
eyebrow="Hello"
description="This is a modal dialog"
size="lg"
footer={
<button onClick={() => setOpen(false)}>Close</button>
}
>
<p>Dialog content here</p>
</AnimatedDialog>
);
}Props:
open: boolean- Whether the dialog is open (required)onOpenChange: (open: boolean) => void- Callback when dialog state changes (required)title?: string- Dialog titleeyebrow?: string- Eyebrow text above titledescription?: string- Dialog descriptionheader?: ReactNode- Custom header (overrides title/eyebrow/description)footer?: ReactNode- Footer contentsize?: "sm" | "md" | "lg" | "xl" | "full"(default: "lg")className?: string- Additional CSS classes for containercontentClassName?: string- Additional CSS classes for content area
Default Styles:
- Background uses theme background color for proper contrast
- Generous padding (p-6 on mobile, p-12 on desktop) for spacious feel
- Proper viewport spacing (my-12 on mobile, my-20 on desktop)
- Close button with circular background that maintains shape on all screen sizes
- Smooth framer-motion animations with backdrop blur
PageHeroBanner
Hero banner component with image or video background support.
import { PageHeroBanner } from "@opensite/ui/components/page-hero-banner";
<PageHeroBanner
imageUrl="https://example.com/hero.jpg"
alt="Hero banner"
minHeight="600px"
showOverlay={true}
overlayOpacity={0.6}
contentMaxWidth="4xl"
>
<h1>Welcome to Our Site</h1>
<p>Discover amazing content</p>
</PageHeroBanner>Props:
imageUrl?: string- Image URL or Media ID (either imageUrl or videoUrl required)videoUrl?: string- Video URL or Media ID (either imageUrl or videoUrl required)alt?: string- Alt text for image (default: "Hero banner")loading?: "eager" | "lazy"(default: "eager")minHeight?: string(default: "500px")showOverlay?: boolean(default: true)overlayOpacity?: number(default: 0.6)contentMaxWidth?: ContainerMaxWidth(default: "4xl")className?: string- Additional CSS classes- All standard div attributes
Button
Interactive button component with multiple variants and sizes.
import { Button } from "@opensite/ui/components/button";
<Button variant="default" size="md">
Click Me
</Button>Props:
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"(default: "default")size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg"(default: "default")asChild?: boolean- Render as child component using Radix Slot (default: false)- All standard button attributes
shadcn/ui Components
Additional components from shadcn/ui are available:
import { Card, CardHeader, CardContent, CardFooter } from "@opensite/ui/components/card";
import { Badge } from "@opensite/ui/components/badge";
import { Popover, PopoverTrigger, PopoverContent } from "@opensite/ui/components/popover";Content-Specific Blocks
Pre-configured, reusable UI blocks for common content patterns.
AlternatingBlocks
Display content sections with alternating left/right media placement. Uses the Section component for consistent spacing, backgrounds, and optional titles. Located in the about category.
import { AlternatingBlocks } from "@opensite/ui/blocks/about/alternating-blocks";
<AlternatingBlocks
title="Our Journey"
subtitle="About Us"
background="gray"
spacing="xl"
sections={[
{
content: (
<div>
<h3 className="mb-3 text-2xl font-semibold">Our Story</h3>
<p className="text-muted-foreground">Started in 2018...</p>
</div>
),
media: <img src="story.jpg" alt="Our story" />,
mediaLeft: false
},
{
content: <div>...</div>,
media: <img src="mission.jpg" alt="Our mission" />,
mediaLeft: true
}
]}
/>Props:
sections: AlternatingBlockSection[]- Array of content sections (required)content: ReactNode- Content to display (text, headings, etc.)media: ReactNode- Media to display (image, video, icon, etc.)mediaLeft?: boolean- Place media on left side (default: false)
title?: string- Section title (optional)subtitle?: string- Section subtitle/eyebrow (optional)background?: SectionBackground- Background variant ("white" | "gray" | "accent", default: "white")spacing?: SectionSpacing- Vertical spacing ("none" | "sm" | "md" | "lg" | "xl", default: "lg")className?: string- Additional CSS classes for Section wrappercontentClassName?: string- Additional CSS classes for content container
Note: Blocks are now organized by category. Import path includes category: @opensite/ui/blocks/[category]/[block-name]
MediaHoverCtas
Two-column CTA grid that reveals background imagery or color on hover. Located in the cta category.
import { MediaHoverCtas } from "@opensite/ui/blocks/cta/media-hover-ctas";
<MediaHoverCtas
items={[
{
content: (
<div>
<h3 className="mb-3 text-xl font-semibold">Our Mission</h3>
<p className="text-muted-foreground">Deliver remarkable experiences.</p>
</div>
),
onHoverImgSrc: "/images/mission.jpg",
altText: "Our Mission"
},
{
content: (
<div>
<h3 className="mb-3 text-xl font-semibold">Our Vision</h3>
<p className="text-muted-foreground">Build the future of our industry.</p>
</div>
),
initialBackgroundColor: "var(--brand-100)",
onHoverBackgroundColor: "var(--brand-900)"
}
]}
/>Props:
items?: MediaHoverCtaItem[]- Array of CTA items (default: [])content?: ReactNode- Content to render inside the cardonHoverImgSrc?: string- Image URL to reveal on hoverimgHoverClassName?: string- Additional classes for hover imagealtText?: string- Alt text for hover image (leave empty for decorative)cardHref?: string- Optional href to make the card a linkinitialBackgroundColor?: string- CSS color value or variable for base backgroundonHoverBackgroundColor?: string- CSS color value or variable for hover background (ignored when hover image is used)
sectionClassName?: string- Additional classes for section wrappergridClassName?: string- Additional classes for grid containeroptixFlowConfig?: { apiKey: string; compression?: number }- Optional Optix Flow config for@page-speed/img
Block Registry
Semantic registry for AI-driven component selection. Maps semantic concepts to available UI blocks.
import {
BLOCK_REGISTRY,
getBlocksBySemanticTag,
getBlocksByCategory,
searchBlocks
} from "@opensite/ui/registry";
// Get blocks by semantic tag
const aboutBlocks = getBlocksBySemanticTag("about");
// Get blocks by category
const featureBlocks = getBlocksByCategory("features");
// Search blocks
const results = searchBlocks("alternating");Available Functions:
getBlocksBySemanticTag(tag: string)- Find blocks matching semantic taggetBlocksByCategory(category: BlockCategory)- Find blocks in categorygetBlockById(id: string)- Get specific block by IDgetAllBlocks()- Get all registered blocksgetAllCategories()- Get all available categoriessearchBlocks(query: string)- Search blocks by name/description/tags
Block Categories:
- about, features, cta, testimonials, services, hero, footer, header, pricing, team, stats, faq, contact, gallery, timeline, process, benefits, comparison
Styling
For comprehensive styling documentation including all CSS variables, theming guides, and customization examples, see STYLES.md.
CSS Variables
Components use CSS variables for theming. Define these in your global CSS:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
/* ... more variables */
}Tailwind CSS Configuration
Ensure your tailwind.config.js includes the library components:
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@opensite/ui/dist/**/*.{js,mjs}",
],
theme: {
extend: {
// Your custom theme
},
},
};Custom Styling
Override component styles using the className prop:
<Container className="bg-blue-500 text-white px-8">
Custom styled container
</Container>TypeScript
Full TypeScript support with exported types:
import type {
ContainerProps,
ContainerMaxWidth,
SectionProps,
SectionBackground,
SectionSpacing,
AnimatedDialogProps,
PageHeroBannerProps,
AlternatingBlocksProps,
AlternatingBlockSection,
BlockRegistryEntry,
BlockCategory,
} from "@opensite/ui/types";Performance
Bundle Sizes
- Core Components: ≤50KB gzipped
- Individual Components: Container (~1KB), Section (~2.5KB), AnimatedDialog (~5KB), PageHeroBanner (~3KB)
Core Web Vitals
All components are optimized for:
- LCP (Largest Contentful Paint): ≤2.5s
- INP (Interaction to Next Paint): ≤200ms
- CLS (Cumulative Layout Shift): ≤0.1
Tree-Shaking
The library is fully tree-shakable. Import only what you need:
// ✅ Good - Only imports Container (~1KB)
import { Container } from "@opensite/ui/components/container";
// ❌ Avoid - Imports everything (~50KB)
import * as UI from "@opensite/ui";Development
Building
pnpm buildTesting
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with coverage
pnpm test -- --coverageType Checking
pnpm type-checkRequirements
- Node.js: >=18.0.0
- pnpm: >=9.0.0
- React: >=16.8.0
License
MIT
Related Packages
- @opensite/blocks - Ultra-lightweight React rendering runtime
- @opensite/img - Performance-optimized image component
- @opensite/video - Performance-optimized video component
- @opensite/hooks - Custom React hooks library
