add-skeleton
v1.5.0
Published
Zero-dependency CLI to inject customizable React + Tailwind skeleton component source code into your codebase
Maintainers
Readme
add-skeleton
CLI to inject customizable React + Tailwind skeleton components into your codebase.
Zero runtime cost — generates source code you own, no dependencies shipped to your bundle.
- 10 components — Skeleton, Card, Text, Avatar, TableRow, ListItem, Profile, Table, Grid, Comment
- Smart detection — reads tsconfig aliases, framework, package manager automatically
- RSC support — auto-adds
"use client"directive for Next.js App Router - Theme system — centralized design tokens with runtime
<SkeletonProvider>override - 5 CLI commands — add, init, update, remove, check
- Interactive prompts — select components, target directory, preview with dry-run
- Tailwind CSS 3+ — all styling via Tailwind utility classes
- TypeScript — all components fully typed
Requirements
- Node.js >= 18
- React 18+
- Tailwind CSS 3+
Quick Start
npx add-skeleton addThis will:
- Detect your project structure (Next.js, Vite, TypeScript, etc.)
- Read your
tsconfig.jsonimport aliases (e.g.@/*) - Detect Next.js App Router (RSC) and add
"use client"directives - Prompt you to select which components to install
- Write source files directly into
src/components/ui/skeleton/
All Commands
# Interactive install (prompts for components and directory)
npx add-skeleton add
# Install everything with defaults
npx add-skeleton add --yes
# Preview without writing files
npx add-skeleton add --dry-run
# Overwrite existing files
npx add-skeleton add --overwrite
# Create a config file for repeated use
npx add-skeleton init
# Check project setup and dependencies
npx add-skeleton check
# Update installed components to latest version
npx add-skeleton update
# Remove skeleton components from project
npx add-skeleton removeSmart Detection
Import Alias Resolution
The CLI reads your tsconfig.json compilerOptions.paths to detect import aliases:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"~/*": ["./src/*"]
}
}
}The import hint after installation will use your detected alias:
Import components from: @/components/ui/skeletonIf no alias is detected, it falls back to a relative path.
Next.js App Router (RSC) Support
When a Next.js App Router project is detected (has app/ directory with layout.tsx), the CLI automatically prepends "use client"; to all generated files so they work in Server Components.
Framework Detection
Automatically detects: Next.js, Vite, Remix, Astro, Gatsby, CRA
Package Manager Detection
Detects: npm, pnpm, yarn, bun (from lockfiles)
Components
<Skeleton> — Base Primitive
The foundation component. All compositions use this internally.
import { Skeleton } from "@/components/ui/skeleton";
// Simple rectangle
<Skeleton />
// Circle avatar
<Skeleton variant="circle" className="h-10 w-10" />
// Text line
<Skeleton variant="text" className="h-4 w-3/4" />
// With count (multiple lines)
<Skeleton variant="text" count={4} />
// Custom color and no animation
<Skeleton
variant="rounded"
baseColor="bg-gray-100"
animation={false}
className="h-20 w-full"
/>Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | 'rect' \| 'circle' \| 'rounded' \| 'text' | 'rect' | Shape variant |
| width | string \| number | — | CSS width |
| height | string \| number | — | CSS height |
| rounded | string | from theme | Border radius class |
| animation | boolean | true | Toggle pulse animation |
| baseColor | string | from theme | Background color class |
| highlightColor | string | from theme | Shimmer highlight class |
| count | number | 1 | Number of skeleton lines (supports decimals) |
| gap | string | 'gap-2' | Gap between counted lines |
| inline | boolean | false | Render counted lines inline |
| className | string | '' | Tailwind class overrides |
| ...props | HTMLDivAttributes | — | All div attributes pass through |
<SkeletonCard> — Card Layout
import { SkeletonCard } from "@/components/ui/skeleton";
// Default card with image + text
<SkeletonCard />
// Card with avatar and custom lines
<SkeletonCard withAvatar avatarSize="lg" lines={4} />
// Card without image
<SkeletonCard withImage={false} lines={2} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| withImage | boolean | true | Show image block at top |
| imageAspect | string | 'aspect-video' | Image aspect ratio |
| withAvatar | boolean | false | Show avatar circle |
| avatarSize | 'sm' \| 'md' \| 'lg' | 'md' | Avatar circle size |
| lines | number | 3 | Number of text lines |
| rounded | string | from theme | Card border radius |
| gap | string | 'gap-3' | Gap between elements |
| className | string | '' | Tailwind class overrides |
<SkeletonText> — Text Lines
import { SkeletonText } from "@/components/ui/skeleton";
// Default 3 lines
<SkeletonText />
// Custom lines with random widths
<SkeletonText lines={5} randomWidth />
// Short text with custom gap
<SkeletonText lines={2} lineHeight="h-3" lineGap="gap-1" lastLineWidth="w-1/3" />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| lines | number | 3 | Number of text lines |
| lineHeight | string | 'h-3' | Height of each line |
| lineGap | string | 'gap-2' | Gap between lines |
| firstLineWidth | string | 'w-full' | Width of first line |
| lastLineWidth | string | 'w-1/2' | Width of last line |
| randomWidth | boolean | false | Randomize line widths |
| className | string | '' | Tailwind class overrides |
<SkeletonAvatar> — Avatar Circle
import { SkeletonAvatar } from "@/components/ui/skeleton";
// Default avatar
<SkeletonAvatar />
// Large avatar with online status dot
<SkeletonAvatar size="xl" showStatus />
// Custom size
<SkeletonAvatar width="h-14 w-14" />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Preset size |
| width | string | — | Custom width (overrides size) |
| height | string | — | Custom height (overrides size) |
| showStatus | boolean | false | Show online status dot |
| className | string | '' | Tailwind class overrides |
<SkeletonTableRow> — Table Row
import { SkeletonTableRow } from "@/components/ui/skeleton";
// Default 4-column row
<SkeletonTableRow />
// Row with avatar and 3 columns
<SkeletonTableRow withAvatar columns={3} />
// Row with image thumbnail
<SkeletonTableRow withImage columns={5} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| columns | number | 4 | Number of columns |
| columnWidths | string[] | auto | Custom width per column |
| withAvatar | boolean | false | Show avatar circle |
| withImage | boolean | false | Show image thumbnail |
| animated | boolean | true | Toggle animation |
| className | string | '' | Tailwind class overrides |
<SkeletonListItem> — List Item
import { SkeletonListItem } from "@/components/ui/skeleton";
// Default list item
<SkeletonListItem />
// Without avatar, with trailing button
<SkeletonListItem withAvatar={false} withTrailing lines={1} />
// Large avatar variant
<SkeletonListItem avatarSize="lg" lines={3} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| withAvatar | boolean | true | Show avatar circle |
| avatarSize | 'sm' \| 'md' \| 'lg' | 'md' | Avatar size |
| lines | number | 2 | Number of text lines |
| withTrailing | boolean | false | Show trailing element (button placeholder) |
| className | string | '' | Tailwind class overrides |
<SkeletonProfile> — User Profile
import { SkeletonProfile } from "@/components/ui/skeleton";
// Default profile card
<SkeletonProfile />
// Centered with XL avatar
<SkeletonProfile centered avatarSize="xl" lines={4} />
// Without cover image
<SkeletonProfile withCoverImage={false} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| avatarSize | 'md' \| 'lg' \| 'xl' | 'lg' | Avatar circle size |
| withCoverImage | boolean | true | Show cover image banner |
| coverAspect | string | 'aspect-[3/1]' | Cover image aspect ratio |
| lines | number | 3 | Number of bio lines |
| centered | boolean | false | Center align all content |
| className | string | '' | Tailwind class overrides |
<SkeletonTable> — Full Table
import { SkeletonTable } from "@/components/ui/skeleton";
// Default 5-row, 4-column table
<SkeletonTable />
// Striped table with 8 rows
<SkeletonTable rows={8} striped />
// Table without header
<SkeletonTable header={false} columns={6} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| rows | number | 5 | Number of data rows |
| columns | number | 4 | Number of columns |
| columnWidths | string[] | auto | Custom width per column |
| header | boolean | true | Show header row |
| striped | boolean | false | Alternate row shading |
| className | string | '' | Tailwind class overrides |
<SkeletonGrid> — Responsive Grid
import { SkeletonGrid } from "@/components/ui/skeleton";
// Default card grid
<SkeletonGrid />
// Image grid with 9 items
<SkeletonGrid variant="image" items={9} columns={3} />
// Avatar grid
<SkeletonGrid variant="avatar" items={4} columns={2} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| items | number | 6 | Number of grid items |
| columns | number | 3 | Number of columns (responsive) |
| variant | 'card' \| 'image' \| 'avatar' | 'card' | Grid item type |
| aspect | string | 'aspect-square' | Aspect ratio (image variant) |
| gap | string | 'gap-4' | Gap between items |
| className | string | '' | Tailwind class overrides |
<SkeletonComment> — Comment Thread
import { SkeletonComment } from "@/components/ui/skeleton";
// Single comment
<SkeletonComment />
// Nested reply
<SkeletonComment nested lines={2} />
// Comment without action bar
<SkeletonComment showActions={false} />Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| withAvatar | boolean | true | Show avatar circle |
| lines | number | 3 | Number of text lines |
| nested | boolean | false | Indent as reply |
| showActions | boolean | true | Show like/reply action bar |
| className | string | '' | Tailwind class overrides |
Theme Customization
All components read from a centralized theme file. Edit theme.ts to change colors, animation speed, border radius, and sizes globally.
// theme.ts
export const skeletonTheme = {
colors: {
base: "bg-slate-200 dark:bg-slate-700",
highlight: "bg-slate-300 dark:bg-slate-600",
muted: "bg-slate-100 dark:bg-slate-800",
},
animation: {
durations: { slow: "2s", normal: "1.5s", fast: "0.8s" },
types: { pulse: "animate-pulse", shimmer: "skeleton-shimmer", wave: "skeleton-wave" },
},
radius: {
none: "rounded-none", sm: "rounded-sm", md: "rounded-md",
lg: "rounded-lg", xl: "rounded-xl", "2xl": "rounded-2xl", full: "rounded-full",
},
sizes: {
xs: { height: "h-2", width: "w-16" },
sm: { height: "h-3", width: "w-24" },
md: { height: "h-4", width: "w-32" },
lg: { height: "h-6", width: "w-48" },
xl: { height: "h-8", width: "w-64" },
},
text: {
lineHeight: "h-4",
lineGap: "gap-2",
firstLineWidth: "w-full",
lastLineWidth: "w-1/2",
},
};Runtime Theme Override
Wrap components with <SkeletonProvider> to override theme at runtime:
import { SkeletonProvider, SkeletonCard } from "@/components/ui/skeleton";
function App() {
return (
<SkeletonProvider theme={{
colors: { base: "bg-indigo-100 dark:bg-indigo-900" },
animation: { durations: { normal: "1s" } },
}}>
<SkeletonCard />
</SkeletonProvider>
);
}Configuration
Run npx add-skeleton init to create a skeleton.config.json:
{
"path": "src/components/ui/skeleton",
"animation": "pulse",
"baseColor": "bg-slate-200 dark:bg-slate-700",
"highlightColor": "bg-slate-300 dark:bg-slate-600",
"radius": "md",
"speed": "normal"
}| Key | Type | Default | Description |
|-----|------|---------|-------------|
| path | string | 'src/components/ui/skeleton' | Install directory |
| animation | 'pulse' \| 'shimmer' \| 'wave' | 'pulse' | Default animation |
| baseColor | string | 'bg-slate-200 dark:bg-slate-700' | Background color |
| highlightColor | string | 'bg-slate-300 dark:bg-slate-600' | Shimmer color |
| radius | string | 'md' | Default border radius |
| speed | 'slow' \| 'normal' \| 'fast' | 'normal' | Animation speed |
CLI Options
npx add-skeleton add [options]
Options:
--cwd <path> Working directory (default: current dir)
--overwrite Overwrite existing files
--dry-run Preview files without writing
--yes Skip prompts and use defaults
--verbose Show detailed output
-h, --help Display help
npx add-skeleton init [options]
Options:
--cwd <path> Working directory (default: current dir)
--yes Skip prompts and use defaults
-h, --help Display help
npx add-skeleton update [options]
Options:
--cwd <path> Working directory (default: current dir)
--dry-run Preview changes without writing
--verbose Show detailed output
-h, --help Display help
npx add-skeleton remove [options]
Options:
--cwd <path> Working directory (default: current dir)
--yes Skip confirmation prompt
-h, --help Display help
npx add-skeleton check [options]
Options:
--cwd <path> Working directory (default: current dir)
--verbose Show detailed output
-h, --help Display helpFile Structure
After installation, your project will contain:
src/components/ui/skeleton/
├── index.ts # Barrel exports
├── theme.ts # Design tokens and provider
├── primitives.tsx # Base <Skeleton /> component
├── card.tsx # SkeletonCard
├── text.tsx # SkeletonText
├── avatar.tsx # SkeletonAvatar
├── table-row.tsx # SkeletonTableRow
├── list-item.tsx # SkeletonListItem
├── profile.tsx # SkeletonProfile
├── table.tsx # SkeletonTable
├── grid.tsx # SkeletonGrid
└── comment.tsx # SkeletonCommentLicense
MIT
