Foundational UI component library for OpenSite Semantic Site Builder with tree-shakable exports and abstract styling
npm install @opensite/uiFoundational UI component library for the OpenSite Semantic Site Builder ecosystem. Provides tree-shakable, performance-optimized components with abstract styling support.
- 🎨 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
> Below you can see the wide range of layouts that are available automatically, enabling a modern UI experience for users. And since the component was specifically engineered for our Semantic UI engine, in addition to the default layout and style variants.
``bash`
pnpm add @opensite/uior
npm install @opensite/ui
This library requires React 16.8.0 or higher:
`bash`
pnpm add react react-dom
For optimal bundle sizes, import components individually:
`tsx
// 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";
`
`tsx`
// Import all (larger bundle)
import * as UI from "@opensite/ui";
Layout container for consistent content width and centering.
`tsx
import { Container } from "@opensite/ui/components/container";
Page Content
`
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 wrapper with optional title, subtitle, and background variants.
`tsx
import { Section } from "@opensite/ui/components/section";
id="features"
title="Our Features"
subtitle="What we offer"
background="gradient"
spacing="lg"
>
Section content here
Props:
-
id?: string - Section ID for anchor links
- title?: string - Section title (renders as h2)
- subtitle?: string - Section subtitle/eyebrow
- background?: "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$3
Animated modal dialog component using framer-motion with polished default styles.
`tsx
import { AnimatedDialog } from "@opensite/ui/components/animated-dialog";
import { useState } from "react";function MyComponent() {
const [open, setOpen] = useState(false);
return (
open={open}
onOpenChange={setOpen}
title="Welcome"
eyebrow="Hello"
description="This is a modal dialog"
size="lg"
footer={
}
>
Dialog content here
);
}
`Props:
-
open: boolean - Whether the dialog is open (required)
- onOpenChange: (open: boolean) => void - Callback when dialog state changes (required)
- title?: string - Dialog title
- eyebrow?: string - Eyebrow text above title
- description?: string - Dialog description
- header?: ReactNode - Custom header (overrides title/eyebrow/description)
- footer?: ReactNode - Footer content
- size?: "sm" | "md" | "lg" | "xl" | "full" (default: "lg")
- className?: string - Additional CSS classes for container
- contentClassName?: string - Additional CSS classes for content areaDefault 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
$3
Hero banner component with image or video background support.
`tsx
import { PageHeroBanner } from "@opensite/ui/components/page-hero-banner"; imageUrl="https://example.com/hero.jpg"
alt="Hero banner"
minHeight="600px"
showOverlay={true}
overlayOpacity={0.6}
contentMaxWidth="4xl"
>
Welcome to Our Site
Discover amazing content
`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$3
Interactive button component with multiple variants and sizes.
`tsx
import { Button } from "@opensite/ui/components/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$3
Additional components from shadcn/ui are available:
`tsx
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";
`$3
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.`tsx
import { AlternatingBlocks } from "@opensite/ui/blocks/about/alternating-blocks"; title="Our Journey"
subtitle="About Us"
background="gray"
spacing="xl"
sections={[
{
content: (
Our Story
Started in 2018...
),
media:
,
mediaLeft: false
},
{
content: ...,
media:
,
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 wrapper
- contentClassName?: string - Additional CSS classes for content containerNote: 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.`tsx
import { MediaHoverCtas } from "@opensite/ui/blocks/cta/media-hover-ctas"; items={[
{
content: (
Our Mission
Deliver remarkable experiences.
),
onHoverImgSrc: "/images/mission.jpg",
altText: "Our Mission"
},
{
content: (
Our Vision
Build the future of our industry.
),
initialBackgroundColor: "var(--brand-100)",
onHoverBackgroundColor: "var(--brand-900)"
}
]}
/>
`Props:
-
items?: MediaHoverCtaItem[] - Array of CTA items (default: [])
- content?: ReactNode - Content to render inside the card
- onHoverImgSrc?: string - Image URL to reveal on hover
- imgHoverClassName?: string - Additional classes for hover image
- altText?: string - Alt text for hover image (leave empty for decorative)
- cardHref?: string - Optional href to make the card a link
- initialBackgroundColor?: string - CSS color value or variable for base background
- onHoverBackgroundColor?: string - CSS color value or variable for hover background (ignored when hover image is used)
- sectionClassName?: string - Additional classes for section wrapper
- gridClassName?: string - Additional classes for grid container
- optixFlowConfig?: { apiKey: string; compression?: number } - Optional Optix Flow config for @page-speed/img$3
Semantic registry for AI-driven component selection. Maps semantic concepts to available UI blocks.
`tsx
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 tag
- getBlocksByCategory(category: BlockCategory) - Find blocks in category
- getBlockById(id: string) - Get specific block by ID
- getAllBlocks() - Get all registered blocks
- getAllCategories() - Get all available categories
- searchBlocks(query: string) - Search blocks by name/description/tagsBlock 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.
$3
Components use CSS variables for theming. Define these in your global CSS:
`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 /
}
`$3
Ensure your
tailwind.config.js includes the library components:`js
module.exports = {
content: [
"./src/*/.{js,ts,jsx,tsx}",
"./node_modules/@opensite/ui/dist/*/.{js,mjs}",
],
theme: {
extend: {
// Your custom theme
},
},
};
`$3
Override component styles using the
className prop:`tsx
Custom styled container
`TypeScript
Full TypeScript support with exported types:
`tsx
import type {
ContainerProps,
ContainerMaxWidth,
SectionProps,
SectionBackground,
SectionSpacing,
AnimatedDialogProps,
PageHeroBannerProps,
AlternatingBlocksProps,
AlternatingBlockSection,
BlockRegistryEntry,
BlockCategory,
} from "@opensite/ui/types";
`Performance
$3
- Core Components: ≤50KB gzipped
- Individual Components: Container (~1KB), Section (~2.5KB), AnimatedDialog (~5KB), PageHeroBanner (~3KB)
$3
All components are optimized for:
- LCP (Largest Contentful Paint): ≤2.5s
- INP (Interaction to Next Paint): ≤200ms
- CLS (Cumulative Layout Shift): ≤0.1
$3
The library is fully tree-shakable. Import only what you need:
`tsx
// ✅ Good - Only imports Container (~1KB)
import { Container } from "@opensite/ui/components/container";// ❌ Avoid - Imports everything (~50KB)
import * as UI from "@opensite/ui";
`Development
$3
`bash
pnpm build
`pnpm build also regenerates:-
package.json export maps (via generate:exports)
- registry-export.json (via scripts/export-registry.js)If you change a block's design/intent, update its registry metadata in
src/registry/blocks.ts before building so the exported JSON stays accurate.$3
`bash
Run tests
pnpm testRun tests in watch mode
pnpm test:watchRun tests with coverage
pnpm test -- --coverage
`$3
`bash
pnpm type-check
``- Node.js: >=18.0.0
- pnpm: >=9.0.0
- React: >=16.8.0
MIT
- @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