@ofi-summerai/markui
v0.1.13
Published
Mark UI component library — React + Tailwind CSS 4 + shadcn/ui
Downloads
1,520
Maintainers
Readme
@ofi-summerai/markui
Full documentation: github.com/OFI-Summer-AI/mark-ui
A production-ready React component library built on shadcn/ui and Radix UI, styled with Tailwind CSS 4. Ships 47 accessible UI primitives plus a suite of higher-level custom components for marketing and dashboard applications.
Installation
# npm
npm i @ofi-summerai/markui
# pnpm
pnpm add @ofi-summerai/markui
# yarn
yarn add @ofi-summerai/markuiRequired peer dependencies
npm i lucide-react recharts react-markdown remark-gfm sonnerOptional (install only what you use):
npm i framer-motion # ShineBorderButton
npm i react-router-dom # BreadcrumbRouter, AppHeaderActions
npm i @tanstack/react-table # DynamicTable
npm i react-day-picker date-fns # Calendar / date picker
npm i cmdk embla-carousel-react input-otp vaul # Other shadcn primitivesSet up styles with Tailwind CSS
Important: Follow these steps carefully to avoid a PostCSS build error.
The error you'll see if done wrong:
[plugin:vite:css] [postcss] @layer base is used but no matching @tailwind base directive is present.This happens because markui's stylesheet uses Tailwind's @layer base internally. When imported from a .tsx file, PostCSS processes it in isolation — without the @tailwind base directive — and crashes.
Correct setup — add to src/index.css:
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@import '@ofi-summerai/markui/style.css';The @import must come after the three @tailwind directives.
Do NOT import it in any .tsx or .ts file:
// Remove this from any component file
import '@ofi-summerai/markui/style.css'| Import location | @tailwind base visible? | Result |
|----------------|--------------------------|--------|
| src/index.css | Yes | Builds correctly |
| Any .tsx component | No | PostCSS crashes |
Vite processes CSS imported from component files in isolation. The @layer base directive inside markui/style.css requires @tailwind base to already be declared in the same processing context, which only exists in src/index.css.
Quick Start
import { Button } from '@ofi-summerai/markui/primitives'
import { KPICard } from '@ofi-summerai/markui/components'
import { TrendingUp } from 'lucide-react'
export default function Dashboard() {
return (
<div className="p-6 space-y-4">
<div className="grid grid-cols-3 gap-4">
<KPICard
title="Total Reach"
value="124,500"
trend={12.4}
trendLabel="vs last month"
icon={<TrendingUp size={18} />}
/>
<KPICard
title="Engagement Rate"
value="4.8%"
trend={-1.2}
trendLabel="vs last week"
/>
<KPICard
title="Posts Published"
value={38}
trend={5.0}
trendLabel="this month"
/>
</div>
<div className="flex gap-2">
<Button>Create Post</Button>
<Button variant="outline">View Analytics</Button>
<Button variant="ghost">Settings</Button>
</div>
</div>
)
}Component Overview
@ofi-summerai/markui — Charts Props Reference
Available Chart Components
| Component | Export Name |
|---|---|
| Bar Chart | BarChartComponent |
| Line Chart | LineChartComponent |
| Pie Chart | PieChartComponent |
BarChartComponent
Import
import { BarChartComponent } from "@ofi-summerai/markui";Props
| Prop | Type | Required | Description |
|---|---|---|---|
| data | Record<string, unknown>[] | ✅ | Array of data objects |
| dataKeys | string[] | ✅ | Fields in data to render as bars |
| xKey | string | ✅ | Field in data to use as the X axis |
| title | string | ❌ | Card title shown above the chart |
| description | string | ❌ | Subtitle shown below the title |
| className | string | ❌ | Additional CSS classes |
Single Bar Example
<BarChartComponent
data={[
{ month: "Jan", revenue: 10 },
{ month: "Feb", revenue: 20 },
{ month: "Mar", revenue: 15 },
]}
dataKeys={["revenue"]}
xKey="month"
title="Monthly Revenue"
/>Multiple Bars Example
<BarChartComponent
data={[
{ month: "Jan", revenue: 10, expenses: 6 },
{ month: "Feb", revenue: 20, expenses: 12 },
{ month: "Mar", revenue: 15, expenses: 9 },
]}
dataKeys={["revenue", "expenses"]}
xKey="month"
title="Revenue vs Expenses"
description="Monthly comparison"
/>When
dataKeyshas more than one entry, a legend is automatically rendered.
LineChartComponent
Import
import { LineChartComponent } from "@ofi-summerai/markui";Run
cat ../mark-ui/src/components/charts/LineChart.tsxto confirm props.
PieChartComponent
Import
import { PieChartComponent } from "@ofi-summerai/markui";Run
cat ../mark-ui/src/components/charts/PieChart.tsxto confirm props.
Chart Colors
Colors are applied automatically in this order:
| Index | Hex | Preview |
|---|---|---|
| 0 | #CCA23E | Golden amber (primary) |
| 1 | #000000 | Black |
| 2 | #FFFFFF | White |
| 3 | #A07C28 | Amber dark |
| 4 | #333333 | Soft black |
| 5 | #E8D5A3 | Light amber |
Colors cycle back from index 0 if there are more than 6 dataKeys.
Common Errors
| Error | Cause | Fix |
|---|---|---|
| does not provide an export named 'BarChart' | Wrong import name | Use BarChartComponent not BarChart |
| Chart renders empty | Wrong xKey or dataKeys | Make sure keys match your data object fields exactly |
| No bars visible | data is empty or undefined | Check your data source before passing to the component |
Primitives (shadcn/ui)
| Component | Description |
|-----------|-------------|
| Accordion | Vertically stacked expandable sections |
| Alert | Contextual feedback banners (info, warning, error) |
| AlertDialog | Modal dialog requiring user confirmation before an action |
| Avatar | Circular user/brand image with initials fallback |
| Badge | Small status or label indicator |
| Breadcrumb | Hierarchical page location trail |
| Button | Versatile action trigger with multiple variants and sizes |
| Calendar | Date picker calendar grid (uses react-day-picker) |
| Card | Contained surface for grouping related content |
| Carousel | Horizontally scrollable slide container (Embla) |
| Chart | Recharts-based chart container with built-in theming |
| Checkbox | Binary toggle input with indeterminate state support |
| Collapsible | Single section expand/collapse without animation overhead |
| Command | Accessible command palette / combobox (cmdk) |
| Dialog | Modal overlay dialog |
| Drawer | Slide-in panel from screen edge (vaul) |
| DropdownMenu | Floating action menu anchored to a trigger |
| Empty | Placeholder for empty states |
| Field | Form field wrapper combining Label + Input + error message |
| Form | React Hook Form integration with validation messages |
| HoverCard | Rich preview card revealed on hover |
| Input | Single-line text input |
| InputGroup | Input with leading/trailing add-ons |
| InputOtp | One-time password segmented input (input-otp) |
| Label | Accessible form label |
| NavigationMenu | Top-level site navigation with dropdown support |
| Pagination | Page number navigation control |
| Popover | Non-modal floating content panel |
| Portal | Renders children into a portal outside the DOM tree |
| Progress | Linear progress bar |
| ScrollArea | Custom-styled scrollable region |
| Select | Single-value dropdown selector |
| Separator | Horizontal or vertical divider line |
| Sheet | Slide-in side panel (Dialog variant) |
| Sidebar | Collapsible application sidebar with nested nav support |
| Skeleton | Animated loading placeholder shape |
| Slider | Range or value slider input |
| Sonner | Toast notification system (Sonner/Toaster) |
| Switch | Binary toggle switch |
| Table | Accessible HTML table with styled rows and cells |
| Tabs | Tabbed content panels |
| Textarea | Multi-line text input |
| Toggle | Single pressable button that retains active state |
| ToggleGroup | Group of mutually-exclusive or multi-select toggles |
| Tooltip | Short text hint revealed on hover/focus |
| CountrySelector | Flag + country name selector with search |
Custom Components
| Component | Description |
|-----------|-------------|
| BrandLogo | Displays a brand image with automatic initials fallback |
| ErrorState | Full-area error display with optional retry button |
| LoadingState | Centered spinning loader for async content |
| ShineBorderButton | Button with animated gradient border (requires framer-motion) |
| TooltipHover | Enriched tooltip with title, body text, and optional action |
| KPICard | Metric card with value, trend indicator, and icon slot |
| FacebookIcon | Facebook SVG icon |
| InstagramIcon | Instagram SVG icon |
| LinkedInIcon | LinkedIn SVG icon |
| TikTokIcon | TikTok SVG icon |
| DynamicTable | Full-featured data table with sorting, filtering, and pagination |
| AvatarDropdown | User avatar that opens a profile/sign-out dropdown |
| BreadcrumbRouter | Auto-generated breadcrumbs from the current react-router path |
| AppHeaderActions | Header action bar rendering router links, links, buttons, or custom nodes |
| EditImageModal | AI image editing modal with upload, prompt, and preview |
| ChatInput | Chat message input with send button and keyboard shortcut |
| ChatMessage | Single rendered chat message bubble (user or assistant) |
| ChatMessagesList | Scrollable list of ChatMessage components |
| TypingIndicator | Animated three-dot typing indicator |
Exports
The library offers three entry points:
// Full library — all primitives + custom components
import { Button, KPICard, DynamicTable } from '@ofi-summerai/markui'
// Only shadcn/ui primitives
import { Button, Card } from '@ofi-summerai/markui/primitives'
// Only custom components
import { KPICard } from '@ofi-summerai/markui/components'Stylesheet: Add
@import '@ofi-summerai/markui/style.css'to yoursrc/index.css— see Set up styles with Tailwind CSS above.
Theming
The library uses CSS custom properties for all design tokens. Override them in your global stylesheet after importing the stylesheet:
/* your-app/globals.css */
:root {
--primary: #6366f1;
--on-primary: #ffffff;
--primary-container: #e0e7ff;
--secondary: #0f172a;
--background: #ffffff;
--surface: #f8fafc;
--radius: 0.5rem;
}Key CSS Variables
| Variable | Default (light) | Purpose |
|----------|----------------|---------|
| --primary | #D946EF | Brand accent color |
| --secondary | #0b3948 | Secondary brand color |
| --background | #fcfcfb | Page background |
| --surface | #fcfcfb | Card/panel surface |
| --on-surface | #333231 | Text on surface |
| --outline | #a39a8e | Border color |
| --outline-variant | #ebe6e0 | Subtle border color |
| --muted | #f4f4f5 | Muted background |
| --muted-foreground | #71717a | Muted text |
| --radius | 0.625rem | Base border radius |
| --error | #b3261e | Error/destructive color |
| --success | #4ac087 | Success color |
Chart-specific variables --chart-1 through --chart-10 control the default palette used by the Chart primitive.
Dark Mode
Add the .dark class to your <html> element to activate the dark theme:
// Toggle dark mode
document.documentElement.classList.toggle('dark')Both .dark and [data-theme="dark"] selectors are supported:
<html class="dark">
<!-- or -->
<html data-theme="dark">Requirements
- React >= 18.2
- Node >= 18
Documentation
Full per-component documentation lives on GitHub:
