Repository: birobirobiro/awesome-shadcn-ui
Branch: main
Commit: e0ca3df56210
Files: 128
Total size: 493.9 KB
Directory structure:
gitextract_2m4yzxwy/
├── .github/
│ ├── FUNDING.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── add-dates.yml
│ └── format-readme.yml
├── .gitignore
├── DEVELOPMENT.md
├── LICENSE
├── README.md
├── components.json
├── next.config.mjs
├── open-next.config.ts
├── package.json
├── postcss.config.mjs
├── scripts/
│ ├── add-dates.js
│ └── format-readme.js
├── src/
│ ├── app/
│ │ ├── [...not-found]/
│ │ │ └── page.tsx
│ │ ├── api/
│ │ │ ├── github/
│ │ │ │ ├── callback/
│ │ │ │ │ └── route.ts
│ │ │ │ └── device-flow/
│ │ │ │ └── route.ts
│ │ │ └── submit-resource/
│ │ │ └── route.ts
│ │ ├── bookmarks/
│ │ │ ├── error.tsx
│ │ │ └── page.tsx
│ │ ├── categories/
│ │ │ ├── [category]/
│ │ │ │ ├── [id]/
│ │ │ │ │ ├── error.tsx
│ │ │ │ │ └── page.tsx
│ │ │ │ ├── error.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── error.tsx
│ │ │ └── page.tsx
│ │ ├── error.tsx
│ │ ├── global-error.tsx
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── not-found.tsx
│ │ └── page.tsx
│ ├── components/
│ │ ├── github-stars.tsx
│ │ ├── item-card.tsx
│ │ ├── item-grid.tsx
│ │ ├── kibo-ui/
│ │ │ └── theme-switcher/
│ │ │ └── index.tsx
│ │ ├── layout/
│ │ │ ├── footer.tsx
│ │ │ ├── header.tsx
│ │ │ └── page-header.tsx
│ │ ├── logo.tsx
│ │ ├── pagination-controls.tsx
│ │ ├── pr-submission-dialog.tsx
│ │ ├── search-filter-controls.tsx
│ │ ├── sections/
│ │ │ ├── cta-submit.tsx
│ │ │ ├── hero.tsx
│ │ │ ├── items-list.tsx
│ │ │ └── sponsorship.tsx
│ │ ├── sort.tsx
│ │ ├── sponsor-card.tsx
│ │ ├── sponsors/
│ │ │ ├── shadcn-blocks-logo.tsx
│ │ │ ├── shadcn-studio-logo.tsx
│ │ │ ├── shadcn-ui-kit-logo.tsx
│ │ │ └── sponsors.tsx
│ │ ├── theme-toggle.tsx
│ │ └── ui/
│ │ ├── accordion.tsx
│ │ ├── alert-dialog.tsx
│ │ ├── alert.tsx
│ │ ├── aspect-ratio.tsx
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── breadcrumb.tsx
│ │ ├── button-group.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── carousel.tsx
│ │ ├── chart.tsx
│ │ ├── checkbox.tsx
│ │ ├── collapsible.tsx
│ │ ├── combobox.tsx
│ │ ├── command.tsx
│ │ ├── context-menu.tsx
│ │ ├── dialog.tsx
│ │ ├── direction.tsx
│ │ ├── drawer.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── empty.tsx
│ │ ├── field.tsx
│ │ ├── hover-card.tsx
│ │ ├── input-group.tsx
│ │ ├── input-otp.tsx
│ │ ├── input.tsx
│ │ ├── item.tsx
│ │ ├── kbd.tsx
│ │ ├── label.tsx
│ │ ├── marquee.tsx
│ │ ├── menubar.tsx
│ │ ├── multi-select.tsx
│ │ ├── native-select.tsx
│ │ ├── navigation-menu.tsx
│ │ ├── pagination.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── radio-group.tsx
│ │ ├── resizable.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet.tsx
│ │ ├── sidebar.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── sonner.tsx
│ │ ├── spinner.tsx
│ │ ├── switch.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ ├── textarea.tsx
│ │ ├── toggle-group.tsx
│ │ ├── toggle.tsx
│ │ └── tooltip.tsx
│ ├── hooks/
│ │ ├── use-bookmark.ts
│ │ ├── use-categories.ts
│ │ ├── use-debounce.ts
│ │ ├── use-github-auth.ts
│ │ ├── use-mobile.ts
│ │ ├── use-pr-submission.ts
│ │ ├── use-readme.ts
│ │ └── use-website-preview.ts
│ ├── lib/
│ │ ├── compose-refs.ts
│ │ ├── config.ts
│ │ ├── slugs.ts
│ │ └── utils.ts
│ └── providers/
│ ├── providers.tsx
│ └── theme-provider.tsx
├── tsconfig.json
└── wrangler.jsonc
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: ["https://buy.stripe.com/9B6cN6eZq6N136ygPm0Jq02"]
================================================
FILE: .github/pull_request_template.md
================================================
---
name: "feat: Add new awesome resource"
about: "Propose adding a new awesome resource related to shadcn/ui"
labels:
- feature
---
## Submission Options
You can submit resources in two ways:
1. **Via Website**: Use the [awesome-shadcn-ui.vercel.app](https://awesome-shadcn-ui.vercel.app/) submission form for a guided experience
2. **Via GitHub PR**: Use this template to create a pull request directly
## Describe the awesome resource you want to add
**What is it?**
> Briefly explain what this resource is and why it's awesome...
-
## **Which section does it belong to?**
- [ ] Libs and Components
- [ ] Plugins and Extensions
- [ ] Colors and Customizations
- [ ] Animations
- [ ] Tools
- [ ] Websites and Portfolios Inspirations
- [ ] Platforms
- [ ] Ports
- [ ] Design System
- [ ] Boilerplates / Templates
**Additional details (optional)**
> Include screenshots, demos, or any other useful context...
-
## **Checklist**
- [ ] I verified that the resource is listed in alphabetical order within its section.
- [ ] I checked that the resource is not already listed.
- [ ] I provided a clear and concise description of the resource.
- [ ] I included a valid and working link to the resource.
- [ ] I assigned the correct section to the resource.
**Important Notes:**
1. If you are introducing a new section, you must also add it to the `README.md` file and update the table of contents accordingly.
2. This repository focuses on open-source and freely accessible projects. Paid or fully commercial resources will not be accepted.
## Required Table Format
**Format your entry exactly like this:**
```markdown
| Name | Description | [Link](Your_Link_Here) |
```
**Table Structure:**
- **Name**: The resource name (keep it concise)
- **Description**: Brief description of what the resource does
- **Link**: Working link to the resource
- **Date**: Leave empty - our system adds this automatically when merged
**Formatting Rules:**
- Each entry must be on a single line
- Use proper markdown table syntax with `|` separators
- Don't add dates manually - the system handles this
- Ensure your link is working and accessible
Thank you for contributing to the awesome-shadcn/ui repository!
================================================
FILE: .github/workflows/add-dates.yml
================================================
name: Add Dates to New Resources
on:
push:
branches:
- main
paths:
- 'README.md'
jobs:
add-dates:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Add dates to new resources
run: node scripts/add-dates.js
- name: Commit changes (if any)
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add README.md
git diff --quiet && git diff --staged --quiet || git commit -m "Add dates to new resources"
git push
================================================
FILE: .github/workflows/format-readme.yml
================================================
name: Format README
on:
pull_request:
paths:
- "README.md"
workflow_dispatch:
jobs:
format-readme:
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Format README
run: node scripts/format-readme.js
- name: Commit changes (if any)
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add README.md
git diff --quiet && git diff --staged --quiet || git commit -m "Format README.md"
# Empurra para a branch do PR
git push origin HEAD:${{ github.head_ref }}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
.open-next/
.agents
.claude
.mcp.json
================================================
FILE: DEVELOPMENT.md
================================================
# Development Guide
This guide covers the development setup, architecture, and configuration of the awesome-shadcn-ui website.
## Quick Start
```bash
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
```
## Project Structure
```
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ └── github/ # GitHub OAuth & PR submission
│ ├── globals.css # Global styles
│ └── layout.tsx # Root layout
├── components/ # React components
│ ├── ui/ # shadcn/ui components
│ ├── item-card.tsx # Resource card component
│ └── pr-submission-dialog.tsx
├── hooks/ # Custom React hooks
│ ├── use-bookmark.ts # Bookmark management
│ ├── use-debounce.ts # Search debouncing
│ ├── use-github-auth.ts # GitHub OAuth flow
│ ├── use-pr-submission.ts # PR creation logic
│ └── use-readme.ts # README parsing
├── lib/ # Utilities & configuration
│ ├── config.ts # Centralized config
│ └── utils.ts # Helper functions
└── providers/ # React context providers
├── theme-provider.tsx
└── providers.tsx
```
## Configuration
### Centralized Config (`src/lib/config.ts`)
All configuration is centralized in one file:
```typescript
export const GITHUB_CONFIG = {
CLIENT_ID: "Ov23lizgfZ4yKq0NxcTm", // GitHub OAuth App
REPO_OWNER: "birobirobiro", // Repository owner
REPO_NAME: "awesome-shadcn-ui", // Repository name
DEVICE_FLOW_URL: "https://github.com/login/device/code",
ACCESS_TOKEN_URL: "https://github.com/login/oauth/access_token",
SCOPES: ["repo"], // Required permissions
FORK_CREATION_DELAY: 5000, // Delay for fork creation
};
export const PR_TEMPLATE = {
HEADER: { /* PR template structure */ },
CATEGORIES: [ /* Available categories */ ],
CHECKLIST_ITEMS: { /* Automated checklist */ }
};
export const ERROR_MESSAGES = { /* Error messages */ };
export const STATUS_MESSAGES = { /* Status messages */ };
```
## Key Features
### Resource Display
- **Source**: Fetches from GitHub README.md
- **Parsing**: `use-readme.ts` hook parses markdown tables
- **Caching**: 30-minute cache to reduce API calls
- **Categories**: Automatically groups by README sections
### Search & Filtering
- **Real-time search** with debouncing (300ms)
- **Category filtering** with URL state management
- **Layout switching** (compact, grid, row)
- **Bookmark system** with localStorage persistence
### PR Submission System
- **GitHub OAuth**: Device flow for secure authentication
- **One-time access**: No credential storage
- **Automated workflow**:
1. Check/create user fork
2. Create feature branch
3. Update README with new resource
4. Create pull request with template
- **Duplicate prevention**: Checks existing resources
- **Alphabetical sorting**: Maintains README organization
### GitHub Integration
#### OAuth Flow (`use-github-auth.ts`)
```typescript
// 1. Start device flow
const { userCode, verificationUri } = await startDeviceFlow();
// 2. User authorizes on GitHub
// 3. Poll for access token
// 4. Get user info and create authenticated Octokit
```
#### PR Creation (`use-pr-submission.ts`)
```typescript
// 1. Check/create fork
// 2. Create branch from latest commit
// 3. Fetch latest README from upstream
// 4. Insert new resource alphabetically
// 5. Commit changes
// 6. Create PR with template
```
## UI Components
### shadcn/ui Integration
- **Components**: Button, Dialog, Input, Select, Badge, etc.
- **Theming**: Dark/light mode with next-themes
- **Styling**: Tailwind CSS with custom design system
- **Accessibility**: Built-in ARIA support
### Custom Components
- **ItemCard**: Displays resource information
- **PRSubmissionDialog**: Handles GitHub authentication and form
- **LayoutSwitcher**: Toggle between view modes
- **SearchBar**: Real-time search with debouncing
## Data Flow
```
GitHub README.md → use-readme.ts → Resource[] → UI Components
↓
User Submission → PR Dialog → GitHub OAuth → PR Creation
```
## Development Workflow
### Adding New Features
1. **Hooks**: Add custom logic in `src/hooks/`
2. **Components**: Create reusable components in `src/components/`
3. **API**: Add endpoints in `src/app/api/`
4. **Config**: Update centralized config in `src/lib/config.ts`
### Environment Variables
```bash
# No environment variables required
# All config is in src/lib/config.ts
```
### Testing
```bash
# Run type checking
npm run type-check
# Run linting
npm run lint
# Build check
npm run build
```
## Dependencies
### Core
- **Next.js 15.2.4**: React framework with App Router
- **React 19**: UI library
- **TypeScript 5.8.3**: Type safety
### UI & Styling
- **shadcn/ui**: Component library (Radix UI primitives)
- **Tailwind CSS 4.1.11**: Utility-first CSS
- **next-themes 0.4.6**: Theme management
- **Lucide React 0.509.0**: Icons
- **Framer Motion 11.0.0**: Animations
### GitHub Integration
- **@octokit/rest 22.0.0**: GitHub API client
- **Device Flow OAuth**: Secure authentication
### Utilities
- **clsx 2.1.1**: Conditional classes
- **tailwind-merge 2.6.0**: Tailwind class merging
- **sonner 1.7.4**: Toast notifications
- **class-variance-authority 0.7.1**: Component variants
- **cmdk 1.0.0**: Command palette
## Contributing
1. **Fork the repository**
2. **Create feature branch**: `git checkout -b feature/amazing-feature`
3. **Make changes** following the existing patterns
4. **Test thoroughly** with different scenarios
5. **Submit PR** with clear description
## Architecture Decisions
### Why Device Flow OAuth?
- **Security**: No client secrets in frontend
- **User-friendly**: No redirects, works everywhere
- **Temporary**: One-time access, no permanent storage
### Why Centralized Config?
- **Maintainability**: Single source of truth
- **Type Safety**: TypeScript constants
- **Consistency**: Same values across all files
### Why README as Data Source?
- **User Readme View**: Easily User Viewable
- **Simplicity**: No database required
- **Version Control**: Changes tracked in Git
- **Transparency**: Public data source
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2024 João Inácio Neto
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
awesome-shadcn/ui
A curated list of awesome things related to shadcn/ui
Created by birobirobiro.dev
Site by bankkroll.xyz
Sponsored by
## Libs and Components
| Name | Description | Link | Date |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ---------- |
| 21st.dev | Open source npm for shadcn/ui components. Also: Dribble for design engineers. Install UI components via shadcn CLI, or publish your own. | [Link](https://21st.dev/) | 2024-12-06 |
| 8bitcn.com | A set of retro-designed, accessible components and a code distribution platform. Open Source. Open Code. | [Link](https://www.8bitcn.com/) | 2025-04-12 |
| aceternity-ui | Copy paste the most trending react components without having to worry about styling and animations. | [Link](https://ui.aceternity.com/) | 2024-12-06 |
| agents-ui | Agents UI is LiveKit’s open source component library built with React and shadcn for designing voice agent interfaces. Start with production-ready defaults, then customize every detail to match your brand. | [Link](https://livekit.io/ui) | 2026-03-04 |
| animated-header | Vercel-like animated header. | [Link](https://github.com/mehrdadrafiee/animated-header) | 2025-10-20 |
| animated-tabs | Vercel-like animated tabs. | [Link](https://github.com/mehrdadrafiee/animated-tabs) | 2025-04-06 |
| assistant-ui | React Components for AI Chat. | [Link](https://github.com/Yonom/assistant-ui) | 2024-09-23 |
| audio/ui | A set of accessible and composable Audio UI components. Built on top of shadcn/ui, it's designed for you to copy, paste, and own. | [Link](https://github.com/ouestlabs/audio-ui) | 2025-11-20 |
| autocomplete-select-shadcn-ui | Autocomplete component built with shadcn/ui and Fancy Multi Select by Maximilian Kaske. | [Link](https://www.armand-salle.fr/post/autocomplete-select-shadcn-ui) | 2024-04-07 |
| auto-form | A React component that automatically creates a shadcn/ui form based on a zod schema. | [Link](https://github.com/vantezzen/auto-form) | 2024-04-29 |
| async-select | Async Select component built with shadcn/ui with debounce search. | [Link](https://async.rdsx.dev) | 2024-07-22 |
| berlix | Animated components library built using Tailwind CSS and Motion | [Link](https://berlix.vercel.app) | 2025-06-10 |
| big-calendar | A modern, feature-rich calendar application with multiple viewing options built using Next.js, TypeScript, and Tailwind CSS. | [Link](https://github.com/lramos33/big-calendar) | 2025-03-08 |
| billingsdk | Modern, type-safe billing and subscription management components for React, built with TypeScript and Tailwind CSS. Designed to work seamlessly alongside shadcn/ui by [Dodo Payments](https://dodopayments.com/). [GitHub](https://github.com/dodopayments/billingsdk) | [Link](https://billingsdk.com/) | 2025-09-06 |
| billui | Open source billing components for React built with Shadcn. Pricing cards, payment methods, invoice history and more. | [Link](https://github.com/commet-labs/billui) | 2025-12-25 |
| blocks.so | A set of clean, modern building blocks to copy and paste into your apps. Works with all React frameworks. | [Link](https://github.com/ephraimduncan/blocks) | 2025-09-06 |
| buouui | A UI component library and template suite based on shadcn/ui with stunning landing pages, templates, and rich animations. | [Link](https://buouui.com) | 2025-04-06 |
| bundui | A collection of reusable animated components built with Tailwind CSS and Framer Motion. | [Link](https://bundui.io) | 2024-09-23 |
| calendar | React/shadcn full calendar like Google Calendar | [Link](https://github.com/charlietlamb/calendar) | 2024-05-03 |
| calendar-cn | A beautifully crafted calendar component built with shadcn/ui and Tailwind CSS, inspired by Notion Calendar. Week view, dark mode, and more. | [Link](https://github.com/vmnog/calendarcn) | 2026-03-05 |
| capture-photo | Browser-based React component for camera functionalities in web applications. | [Link](https://github.com/UretzkyZvi/capture-photo) | 2024-05-06 |
| carouselcn | Copy-paste carousel components and examples for your react apps | [Link](https://github.com/mnove/carouselcn) | 2026-01-27 |
| cascader-shadcn | A cascading dropdown menu component for selecting hierarchical data like locations, categories, or organizational structures. | [Link](https://github.com/Ademking/cascader-shadcn) | 2025-12-04 |
| chanhdai-components | A collection of reusable components. Trusted registry for shadcn/ui. | [Link](https://chanhdai.com/components) | 2026-03-01 |
| clerk-elements | Composable components for building custom UIs on top of Clerk's APIs. | [Link](https://clerk.com/docs/elements/examples/shadcn-ui) | 2024-06-07 |
| clerk-shadcn-theme | Synchronize Clerk SignIn/SignUp components with shadcn/ui styles. | [Link](https://github.com/stormynight9/clerk-shadcn-theme) | 2024-06-07 |
| commerce-ui | Components, blocks and examples to build e-commerce storefronts and apps. | [Link](https://github.com/stackzero-labs/ui) | 2025-02-20 |
| confirm-dialog | A confirm dialog component built with shadcn/ui. | [Link](https://github.com/Aslam97/react-confirm-dialog) | 2024-07-02 |
| country-state-dropdown | Component built with Nextjs, Tailwindcss, shadcn/ui & Zustand. | [Link](https://github.com/Jayprecode/country-state-dropdown) | 2024-02-22 |
| creatorem/ui | Missing awesome shadcn components (like Tour, Stepper, QRCode Motion Dialog -> to imitate native behaviour ...) built on top of radix primitives and motion. | [Link](https://github.com/creatorem/ui) | 2025-12-19 |
| credenza | Ready-made responsive modal component for shadcn/ui. | [Link](https://github.com/redpangilinan/credenza) | 2024-06-07 |
| crypto-charts | Crypto charts made for shadcn/ui using PythNetwork. | [Link](https://github.com/jstnw10/crypto-charts) | 2024-07-16 |
| cult-ui | Curated set of animated shadcn-style React components. | [Link](https://www.cult-ui.com/) | 2024-05-29 |
| custom-admin-dashboard | A minimal, open-source ecommerce admin dashboard template built with shadcn/ui and Next.js. Includes products, products creation and details page, order, customer, and settings pages. | [Link](https://github.com/S5SAJID/custom-ecom) | 2025-09-06 |
| data-command | Component for building dynamic command palettes with API-powered data. | [Link](https://shadcn.davidsling.in/components/data-command) | 2025-09-06 |
| date-range-picker-for-shadcn | Multi-month views, text entry, preset ranges, responsive design, and date range comparisons. | [Link](https://github.com/johnpolacek/date-range-picker-for-shadcn) | 2024-04-29 |
| date-time-picker-shadcn | Datetime Picker for shadNext Project. | [Link](https://shadcn-datetime-picker.vercel.app) | 2024-07-16 |
| date-time-range-picker-shadcn | Fully featured date-time range picker with multi-month views, timezone support, preset ranges, and modular components for date and time selection. | [Link](https://date-time-range-picker.vercel.app/) | 2025-03-08 |
| datetime-picker | Datetime picker with timezone support, min/max dates, and month/year selection. | [Link](https://shadcn-datetime-picker-xi.vercel.app) | 2024-07-16 |
| dnd-dashboard | Dashboard with drop-to-swap layouts using Next.js, shadcn/ui, and swapy. | [Link](https://github.com/olliethedev/dnd-dashboard) | 2024-10-17 |
| downshift-shadcn-combobox | Combobox/autocomplete component built with shadcn/ui and Downshift. | [Link](https://github.com/TheOmer77/downshift-shadcn-combobox) | 2024-06-27 |
| drag-to-resize-sidebar | Extended shadcn/ui sidebar component with persisted state drag-to-resize functionality. | [Link](https://github.com/lumpinif/drag-to-resize-sidebar) | 2024-11-21 |
| druid/ui | Intercom inspired AI chatbot and UI components built on shadcn/ui. | [Link](https://druidui.com/) | 2024-11-21 |
| drop-drawer | A dropdown menu on desktop and a drawer on mobile devices. | [Link](https://github.com/jiaweing/DropDrawer) | 2025-05-13 |
| dy-comps | shacn/ui & Framer Motion React components — flexible, responsive & easy to drop into any project. | [Link](https://dycomps.oimmi.com/) | 2025-03-08 |
| dynamic-svg-arrow | Connect any two elements with beautiful, animated paths. Control curve shape, routing, layering, arrowheads, gradients, and responsive behavior in real-time. | [Link](https://dsa.hncore.website/) | 2025-10-09 |
| echo-editor | Modern WYSIWYG rich-text editor based on tiptap and shadcn/ui. | [Link](https://github.com/Seedsa/echo-editor) | 2024-06-07 |
| edil-ozi | React components with Gsap, framer motion, and tailwind. | [Link](https://edilozi.pro/) | 2024-06-27 |
| eldora-ui | free and open-source animated components built with React, Typescript, Tailwind CSS, and Framer Motion. | [Link](https://eldoraui.site/) | 2024-12-06 |
| emblor | Customizable, accessible tag input component with shadcn/ui. | [Link](https://github.com/JaleelB/emblor) | 2024-04-29 |
| enhanced-button | Enhanced version of the default shadcn-button component. | [Link](https://github.com/jakobhoeg/enhanced-button) | 2024-04-29 |
| envin | Framework-agnostic, type-safe tool to validate and preview your environment variables - powered by your favorite schema validator. | [Link](https://envin.turbostarter.dev) | 2025-07-07 |
| eo-n/ui | Enhanced UI components built on shadcn’s robust foundation, integrated with Base UI and Tailwind CSS for a modern and customizable design system. | [Link](https://github.com/aeonzz/eo-n) | 2025-04-04 |
| event-timeline-roadmap | A pair of customizable, animated event timeline and roadmap components | [Link](https://roadmap.hncore.website/) | 2025-04-01 |
| extend-ui | Reusable components built on shadcn/ui for web applications. | [Link](https://www.extend-ui.com/) | 2024-11-28 |
| fancy-area | Textarea with @mention support inspired by GitHub's PR comment section. | [Link](https://craft.mxkaske.dev/post/fancy-area) | 2024-06-27 |
| fancy-box | GitHub PR label selector-inspired Combobox with radix-ui components. | [Link](https://craft.mxkaske.dev/post/fancy-box) | 2024-07-11 |
| fancy-multi-select | Multi Select Component inspired by campsite.design and cal.com. | [Link](https://craft.mxkaske.dev/post/fancy-multi-select) | 2024-04-29 |
| fancy-switch | Fancy switch component built with shadcn/ui. | [Link](https://github.com/Aslam97/react-fancy-switch) | 2024-07-11 |
| farmui | Styled and animated component library with npm package support. | [Link](https://farmui.com) | 2024-06-08 |
| file-uploader | File uploader with shadcn/ui and react-dropzone. | [Link](https://github.com/sadmann7/file-uploader) | 2024-06-07 |
| file-vault | File upload component for React. | [Link](https://github.com/ManishBisht777/file-vault) | 2024-06-07 |
| floating-dragable-card | Dragable and resizable card using shadcn/ui elements. | [Link](https://github.com/nishansanjuka/react-drag-card) | 2024-11-13 |
| fusion-ui | Library combining shadcn/ui and MagicUI. | [Link](https://github.com/nyxb-ui/ui) | 2024-07-02 |
| glasscn-ui | shadcn/ui component library with glassmorphism variants, and many additional components. | [Link](https://github.com/itsjavi/glasscn-ui) | 2025-06-10 |
| glitchcn-ui | A terminal-styled cyberpunk component library for Next.js with scanline effects, glowing borders, and monospace typography. | [Link](https://glitchcn-ui.vercel.app/) | 2026-02-06 |
| gluestack-ui | React & React Native Components with Tailwind CSS. | [Link](https://gluestack.io) | 2024-11-08 |
| goey-toast | Morphing toast notifications for React. Organic blob animations, promise tracking, and full customization out of the box | [Link](https://goey-toast.vercel.app/) | 2026-02-14 |
| heroicons-animated | An open-source collection of 316 beautifully animated heroicons for your projects. | [Link](https://heroicons-animated.vercel.app/) | 2026-01-23 |
| hexta-ui | Build stunning websites effortlessly. Modern, responsive, and customizable UI components for Next.js. Copy, adapt, and personalize them. | [Link](https://hextaui.com) | 2025-05-14 |
| ibelick/background-snippet | Ready to use collection of modern background snippets. | [Link](https://bg.ibelick.com/) | 2024-06-09 |
| image-crop-field | Image crop field with shadcn/ui. This component is a wrapper around the react-easy-crop component. | [Link](https://github.com/JsCodeDevlopment/upload-crop-image) | 2025-10-01 |
| image-upload-shadcn | Image upload component. | [Link](https://github.com/kushagrasarathe/image-upload-shadcn) | 2024-10-22 |
| indie-ui | UI components with variants. | [Link](https://github.com/Ali-Hussein-dev/indie-ui) | 2024-06-07 |
| inspira-ui | UI components for animated interfaces in Vue/NuxtJS. | [Link](https://inspira-ui.com/) | 2024-10-22 |
| jolyui | JolyUI is a modern React component library built with TypeScript, Tailwind CSS and Motion. It offers a wide range of customizable and accessible UI components to help you build stunning web applications quickly and efficiently. | [Link](https://github.com/Johuniq/jolyui) | 2026-01-23 |
| junwen-k/ui-x | Additional beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source. | [Link](https://ui-x.junwen-k.dev/) | 2025-02-03 |
| kanban-board | A production‑ready Kanban board built on shadcn/ui with React & Tailwind CSS: zero dependencies, drag‑and‑drop, keyboard accessibility and seamless theming. | [Link](https://shadcn-kanban-board.com/) | 2025-07-15 |
| kibo-ui | Kibo UI is designed to be a more comprehensive library of components that can be used to build more complex applications. | [Link](https://www.kibo-ui.com/overview) | 2025-04-04 |
| kokonut-ui | Free Modern and Customizable components for Next.js. | [Link](https://kokonutui.com/) | 2024-11-08 |
| ktui | Open-source collection of customizable UI components for Tailwind CSS and vanilla JavaScript | [Link](https://github.com/keenthemes/ktui) | 2025-06-10 |
| launch-ui | Landing page components with React, Shadcn/ui and Tailwind. | [Link](https://www.launchuicomponents.com/) | 2024-11-12 |
| lingua-time | Smart datetime picker with natural language input. | [Link](https://github.com/nainglinnkhant/lingua-time) | 2024-10-22 |
| linked-chart | Chart component linked with data-table. | [Link](https://github.com/ardasisbot/linked-chart) | 2025-02-03 |
| lukacho-ui | Next Generation UI Components. | [Link](https://ui.lukacho.com/components) | 2024-07-02 |
| magicui | React components for landing pages with tailwindcss + framer motion. | [Link](https://magicui.design) | 2024-04-25 |
| maily.to | Notion-like powerful email editor. | [Link](https://github.com/arikchakma/maily.to) | 2024-06-15 |
| manfromexistence-ui | Components to build beautiful designs. | [Link](https://github.com/manfromexistence/ui) | 2024-12-26 |
| manifest-ui | Components for ChatGPT Apps and MCP Apps. | [Link](https://ui.manifest.build) | 2025-12-23 |
| matsu-theme | Ghibli Studio inspired theme for shadcn/ui made by Matt Wierzbicki | [Link](https://matsu-theme.vercel.app/) | 2025-04-23 |
| mindmapcn | Beautiful mind maps, works seamlessly with shadcn/ui. | [Link](https://github.com/SSShooter/mindmapcn) | 2026-01-27 |
| minimal-tiptap | Minimal WYSIWYG editor with shadcn/ui and tiptap. | [Link](https://github.com/Aslam97/shadcn-minimal-tiptap) | 2024-06-22 |
| mixcnui | Collection of animated components for Nextjs. | [Link](https://github.com/taqui-786/mixcnui) | 2024-07-07 |
| modal-control-query | A hook to control shadcn modal components using query params | [Link](https://shadcn.davidsling.in/hooks/use-modal-control-query) | 2025-11-02 |
| moleculeui | A modern React component library focused on intuitive interactions and seamless user experiences. | [Link](https://www.moleculeui.design/) | 2025-09-06 |
| multi-selection | Managing multi-selection functionality with highlighter. | [Link](https://github.com/sherifawad/multi-selection-with-add-remove) | 2025-01-21 |
| mvpblocks | Copy-paste beautiful, responsive components without worrying about styling or animations. Build faster, launch sooner. | [Link](https://blocks.mvp-subha.me) | 2025-05-14 |
| mynaui | TailwindCSS and shadcn/ui UI Kit for Figma and React. | [Link](https://mynaui.com/) | 2024-06-22 |
| neobrutalism-components | Neobrutalism-styled Tailwind React and shadcn/ui components. | [Link](https://github.com/ekmas/neobrutalism-components) | 2024-04-07 |
| nextjs-components | Next.js components with TypeScript and shadcn/ui. | [Link](https://components.bridger.to/) | 2024-06-07 |
| nextjs-dnd | Sortable Drag and Drop with Next.js and dnd-kit. | [Link](https://github.com/sujjeee/nextjs-dnd) | 2024-04-09 |
| nextjs-link-pagination | Pagination using Nextjs Links and search params. | [Link](https://shadcn-next-link-pagination.vercel.app) | 2024-07-30 |
| nextjs-multi-image-upload | Compact, responsive file uploader with shadcn/ui, React Hook Form, and cloud support (S3/R2). | [Link](https://github.com/jacksonkasi0/nextjs-multi-image-upload) | 2025-02-23 |
| next-shadcn-dashboard-starter | Admin Dashboard Starter with Nextjs 14 and Shadcn UI. | [Link](https://github.com/Kiranism/next-shadcn-dashboard-starter) | 2024-06-06 |
| next-stepper | Dynamic multi-step form with Next.js and zustand. | [Link](https://github.com/ebulku/next-stepper) | 2024-11-25 |
| novel | Notion-style WYSIWYG editor with AI-powered autocompletion. | [Link](https://github.com/steven-tey/novel) | 2024-06-11 |
| number-flow | React component for number transitions and formatting. | [Link](https://number-flow.barvian.me/) | 2024-10-17 |
| origin-ui | Beautiful UI components with Tailwind CSS and Next.js. | [Link](https://originui.com/) | 2024-10-28 |
| password-input | shadcn/ui custom password input. | [Link](https://gist.github.com/mjbalcueva/b21f39a8787e558d4c536bf68e267398) | 2024-03-28 |
| payment-gateways | Integration of payment gateways with Next.js 14. | [Link](https://github.com/PremPrakashCodes/payment-gateways) | 2024-08-05 |
| pdfx | shadcn/ui-style PDF component library for React. Copy-paste components built on @react-pdf/renderer run pdfx add invoice and own the code. | [Link](https://github.com/akii09/pdfx) | 2026-02-28 |
| phone-input-shadcn-ui | Custom phone number component with shadcn/ui. | [Link](https://www.armand-salle.fr/post/phone-input-shadcn-ui) | 2024-06-07 |
| pittaya-ui | A fully open-source UI library for React, powered by TypeScript and Tailwind CSS. Fast, composable, and ready for production. | [Link](https://github.com/pittaya-ui/ui-kit) | 2026-01-27 |
| planner | Adaptable scheduling component for React. | [Link](https://github.com/UretzkyZvi/planner) | 2024-04-29 |
| plate | AI-powered rich-text editor. | [Link](https://github.com/udecode/plate) | 2024-03-21 |
| plate-select-editor | Rich multi-select editor. | [Link](https://platejs.org/docs/multi-select) | 2024-11-28 |
| pqoqubbw | Open-source animated icons collection. | [Link](https://icons.pqoqubbw.dev/) | 2024-11-21 |
| pricing-page-shadcn | Customizable pricing page with Next.js 14. | [Link](https://github.com/m4nute/pricing-page-shadcn) | 2024-04-07 |
| progress-button | Extended button component with progress UX. | [Link](https://github.com/tomredman/ProgressButton) | 2024-07-10 |
| re-ui | Open-source collection of UI components and animated effects built with React, Typescript, Tailwind CSS, and Motion. Pairs beautifully with shadcn/ui | [Link](https://reui.io/) | 2025-09-06 |
| react-dnd-kit-tailwind-shadcn-ui | Accessible kanban board with dnd-kit. | [Link](https://github.com/Georgegriff/react-dnd-kit-tailwind-shadcn-ui) | 2024-03-27 |
| react-highlight-popover | Headless component for text selection popovers. | [Link](https://react-highlight-popover.omsimos.com) | 2024-10-03 |
| react-pdf-flipbook-viewer | PDF flipbook viewer with zoom and fullscreen. | [Link](https://github.com/mohitkumawat310/react-pdf-flipbook-viewer) | 2024-12-26 |
| react-select | React-select library with shadcn styling. | [Link](https://gist.github.com/ilkou/7bf2dbd42a7faf70053b43034fc4b5a4) | 2024-07-22 |
| react-wheel-picker | iOS-like wheel picker for React with smooth inertia scrolling and infinite loop support. | [Link](https://react-wheel-picker.chanhdai.com) | 2025-09-11 |
| recursive-dnd-kanban-board | Recursive drag and drop kanban board. | [Link](https://github.com/mehrdadrafiee/recursive-dnd-kanban-board) | 2024-10-03 |
| retro-ui | An open source component library, inspred by neo brutalism design system | [Link](https://retroui.dev) | 2025-05-13 |
| roadmap-ui | Components for interactive roadmaps. | [Link](https://github.com/haydenbleasel/roadmap-ui) | 2024-12-26 |
| ruixen-ui | Ruixen UI: Lightweight & Customizable React Library | [Link](https://github.com/ruixenui/ruixen.com) | 2025-12-04 |
| search-address | Interactive address search using OpenStreetMap. | [Link](https://github.com/UretzkyZvi/search-address) | 2024-05-07 |
| shadboard | An admin dashboard template built with Next.js 15, React 19, Tailwind CSS v4, and Shadcn/UI components, featuring starter and full kits for scalable, user-friendly web apps. | [Link](https://github.com/Qualiora/shadboard) | 2025-04-22 |
| shadcn-address-autocomplete | Address autocomplete with Google Places API. | [Link](https://github.com/NiazMorshed2007/shadcn-address-autocomplete) | 2024-07-10 |
| shadcn-admin | Admin Dashboard UI with shadcn/ui and Vite. | [Link](https://github.com/satnaing/shadcn-admin) | 2024-12-27 |
| shadcn-admin-kit | Powerful open-source shadcn components to build beautiful internal tools, admin panels, and dashboards with React | [Link](https://github.com/marmelab/shadcn-admin-kit) | 2025-07-07 |
| shadcn-blocks | Official pre-made customizable components. | [Link](https://ui.shadcn.com/blocks) | 2024-03-27 |
| shadcn-blocks-com | Hundreds of extra blocks built with shadcn/ui. | [Link](https://www.shadcnblocks.com) | 2025-02-23 |
| shadcn-builder | Create beautiful, responsive forms with the easy-to-use form builder and generate React code using shadcn/ui components. | [Link](https://www.shadcn-builder.com/?utm_source=github&utm_content=awesome-shadcn-ui) | 2025-03-31 |
| shadcn-cal | Cal.com monthly calendar replica with shadcn/ui. | [Link](https://shadcn-cal-com.vercel.app/?date=2024-04-29) | 2024-05-03 |
| shadcn-calendar-heatmap | Modern calendar heatmap alternative. | [Link](https://shadcn-calendar-heatmap.vercel.app/) | 2024-07-02 |
| shadcn-calendar-component | Calendar date picker component. | [Link](https://github.com/sersavan/shadcn-calendar-component) | 2024-07-02 |
| shadcn-chat | Customizable chat component. | [Link](https://github.com/jakobhoeg/shadcn-chat) | 2024-04-29 |
| shadcn-carousel-testimonials | Carousel Testimonials component. | [Link](https://github.com/johanguse/shadcn-carousel-testimonials) | 2024-07-16 |
| shadcn-chatbot-kit | Customizable chatbot components. | [Link](https://shadcn-chatbot-kit.vercel.app/) | 2024-12-27 |
| shadcn-color-picker | Color picker with react-color. | [Link](https://shadcn-color-picker.vercel.app/) | 2024-09-23 |
| shadcn-cookies | Sleek and flexible cookie consent component, designed with shadcn/ui | [Link](https://shadcn-cookies.vercel.app/) | 2025-02-06 |
| shadcn-cookie-consent | Customizable cookie consent component. | [Link](https://github.com/r2hu1/shadcn-cookie-consent) | 2024-10-17 |
| shadcn-components-blocks | The ultimate blocks and components for Shadcn UI & Tailwind CSS. | [Link](https://shadcncomponents.dev/) | 2025-09-06 |
| shadcn-country-dropdown | ISO 3166 country selector dropdown. | [Link](https://shadcn-country-dropdown.vercel.app/) | 2024-12-27 |
| shadcn-data-table-advanced-col-opions | DataTable with column resizing. | [Link](https://github.com/danielagg/shadcn-data-table-advanced-col-opions) | 2024-04-07 |
| shadcn-date-picker | Advanced date picker with various features. | [Link](https://date-picker.luca-felix.com) | 2024-07-25 |
| shadcn-drag-and-drop-sort | Drag-and-drop sortable list of pills of different widths using dnd-kit. | [Link](https://github.com/crystaltai/shadcn-drag-and-drop) | 2025-02-03 |
| shadcn-drag-table | Drag-and-drop table component. | [Link](https://github.com/zenoncao/shadcn-drag-table) | 2024-02-22 |
| shadcn-dropzone | File upload component using React-Dropzone, built with accessibility in mind. | [Link](https://github.com/janglad/shadcn-dropzone) | 2025-01-13 |
| shadcn-editor | Lexical editor with shadcn theme. | [Link](https://github.com/htmujahid/shadcn-editor) | 2024-11-08 |
| shadcn-examples | Dozens of advanced shadcn/ui examples. Easily integrate sample applications and components into your project. | [Link](https://shadcnexamples.com) | 2025-06-04 |
| shadcn-extends | Collection of shadcn/ui components. | [Link](https://github.com/lucioew28/extends) | 2024-06-07 |
| shadcn-extension | Open-source component collection. | [Link](https://github.com/BelkacemYerfa/shadcn-extension) | 2024-06-07 |
| shadcn-font-picker | Font picker using shadcn/ui components and google font API. | [Link](https://shadcn-font-picker.vercel.app) | 2025-04-22 |
| shadcn-full-calendar | A feature-rich calendar application built with React, TypeScript, and ShadCN UI components. This project provides a customizable and interactive calendar experience with multiple views, event management, and a modern UI. | [Link](https://github.com/yassir-jeraidi/full-calendar) | 2025-07-07 |
| shadcn-iconpicker | React/shadcn simple icon picker using lucide icons. | [Link](https://icon-picker.alan-courtois.fr/) | 2025-02-20 |
| shadcn-image-cropper | Image cropper with react-image-crop. | [Link](https://github.com/sujjeee/shadcn-image-cropper) | 2024-11-08 |
| shadcn-io | Advanced Shadcn/UI components. | [Link](https://shadcn.io) | 2025-09-06 |
| shadcn-linear-combobox | Linear-style task priority combobox. | [Link](https://github.com/damianricobelli/shadcn-linear-combobox) | 2024-04-25 |
| shadcn-location-picker | Simple google maps location picker. | [Link](https://github.com/brielov/shadcn-location-picker) | 2025-03-04 |
| shadcn-map | A map component built for shadcn/ui using Leaflet and React Leaflet. | [Link](https://shadcn-map.vercel.app/) | 2025-09-30 |
| shadcn-multi-select-component | Multi-select component. | [Link](https://github.com/sersavan/shadcn-multi-select-component) | 2024-06-07 |
| shadcn-number-scrubber | Draggable numeric input component. | [Link](https://github.com/camwebby/shadcn-react-number-scrubber) | 2025-01-07 |
| shadcn-packaged | This is an npm package that exports all shadcn/ui components without the need for a CLI, designed for ease of use. | [Link](https://github.com/anuoua/shadcn-packaged) | 2025-02-27 |
| shadcn-phone-input-2 | Phone input with libphonenumber-js. | [Link](https://github.com/damianricobelli/shadcn-phone-input) | 2024-06-07 |
| shadcn-phone-input | Phone input with country validation. | [Link](https://github.com/omeralpi/shadcn-phone-input) | 2024-03-27 |
| shadcn-portable-text-editor | A headless rich text editor built upon Sanity's Portable Text Editor with opinionated starting styles | | 2025-09-06 |
| shadcn-pricing-page | Responsive pricing component with toggles. | [Link](https://github.com/aymanch-03/shadcn-pricing-page) | 2024-03-08 |
| shadcn-space | Open-source shadcn/ui blocks, components, and templates built with React, Tailwind, and Base UI. | [Link](https://github.com/shadcnspace/shadcnspace) | 2026-02-27 |
| shadcn-spinner | Spinner component. | [Link](https://github.com/allipiopereira/shadcn-spinner) | 2024-12-09 |
| shadcn-stepper | Complete stepper component. | [Link](https://github.com/damianricobelli/stepperize) | 2024-04-25 |
| shadcn-studio | Open Source Registry of Shadcn components and blocks. | [Link](https://shadcnstudio.com/) | 2025-04-24 |
| shadcn-table-maker | Tool for creating dynamic tables. | [Link](https://shadcn-table-maker.vercel.app/) | 2024-12-09 |
| shadcn-table-v2 | Table with server-side features. | [Link](https://github.com/sadmann7/shadcn-table) | 2024-03-27 |
| shadcn-tanstack-form | Seamless shadcn TanStack Form component set. Fully featured with validation support and type-safety. | [Link](https://shadcn-tanstack-form.felipestanzani.com/) | 2025-10-08 |
| shadcn-timeline | Customizable timeline component. | [Link](https://github.com/timDeHof/shadcn-timeline) | 2024-06-22 |
| shadcn-timeline-2 | Alternative timeline component. | [Link](https://timeline.rilcy.app) | 2024-11-08 |
| shadcn-tiptap | Custom Tiptap editor extensions. | [Link](https://github.com/NiazMorshed2007/shadcn-tiptap) | 2024-11-08 |
| shadcn-vaults | Collection of various interactive components & blocks for Internal Tools UI like Dashboard, Monitoring, Admin, CMS, and more. Specifically made for Full-Stack Dev | [Link](https://shadcn-vaults.vercel.app/) | 2025-07-03 |
| shadcn-tree-view | Hierarchical data component. | [Link](https://github.com/mrlightful/shadcn-tree-view) | 2024-09-23 |
| shadcn-ui-blocks | Collection of responsive UI blocks. | [Link](https://shadcn-ui-blocks.vercel.app/) | 2024-06-15 |
| shadcn-ui-expansions | Additional useful components. | [Link](https://github.com/hsuanyi-chou/shadcn-ui-expansions) | 2024-06-07 |
| shadcn-ui-sidebar | Retractable responsive sidebar. | [Link](https://github.com/salimi-my/shadcn-ui-sidebar) | 2024-05-03 |
| shadcn-ui-templates | Free & Premium templates collection. | [Link](https://shadcnui-templates.com) | 2024-09-18 |
| shadcnship | Production-ready shadcn/ui component registry for building modern SaaS applications with Next.js, TypeScript, and Tailwind CSS. | [Link](https://github.com/arnaudvolp/shadcnship) | 2026-01-31 |
| shaduxe-ui | Component variants for shadcn/ui. | [Link](https://ui.shaduxe.com) | 2024-12-27 |
| shadcn-event-calendar | A beautiful and flexible event calendar component inspired by Google Calendar and Notion, built with Shadcn UI, TailwindCSS, and Framer Motion. | [Link](https://shadcn-event-calendar.vercel.app) | 2025-07-16 |
| shsfui | Motion-first React components built with Tailwind CSS + Framer Motion. | [Link](https://www.shsfui.com) | 2025-03-12 |
| shuip | Provides ready-to-use, business-focused components that help you ship faster. | [Link](https://shuip.plvo.dev/docs) | 2025-10-09 |
| siddz-ui | A curated collection of modern, reusable React components. Built with performance and accessibility in mind. Copy, paste, and customize. | [Link](https://siddz.com/components) | 2026-02-13 |
| simple-ai | Components and blocks to easily build AI apps | [Link](https://simple-ai.dev) | 2025-01-21 |
| simple-image-uploader | Image uploader with dnd, validation and previews | [Link](https://simple-image-uploader-bice.vercel.app/) | 2025-03-25 |
| simplekit | Wallet and account component for Wagmi. | [Link](https://github.com/vaunblu/SimpleKit) | 2024-09-18 |
| skiper-ui | Stand out from others with this crazzy ui library built with shad-cn cli | [Link](https://skiper-ui.com/) | 2025-02-03 |
| solanauth | Solana wallet authentication modal. | [Link](https://solanauth.vercel.app/) | 2024-11-25 |
| sortable | Sortable component with dnd-kit. | [Link](https://github.com/sadmann7/sortable) | 2024-04-09 |
| spectrum-ui | Collection using Aceternity UI Magic UI. | [Link](https://github.com/arihantcodes/spectrum-ui) | 2024-11-25 |
| stateful-button | A shadcn/ui button component that provides clear visual feedback with full accessibility support for loading/progress, success, and error states during asynchronous operations. | [Link](https://github.com/nanyx95/Stateful-Button-React) | 2025-09-06 |
| stocks | Stock Picker with Next.js charts. | [Link](https://github.com/aryanvichare/stocks) | 2024-07-07 |
| supabase-shadcn-database-example | supabase + shadcn/ui datatable | [Link](https://github.com/thisisfel1x/supabase-shadcn-database-example) | 2024-12-30 |
| supercharged-shadcn-components | Type-safe form components collection. | [Link](https://github.com/slickwit/supercharged-shadcn-components) | 2024-11-25 |
| svelte-image-uploader | Svelte image uploader with dnd, validation and previews. | [Link](https://svelte-image-uploader.vercel.app/) | 2025-06-10 |
| trable-craft | Drizzle ORM-powered table engine that auto-generates tables from your schema. Built on TanStack Table with server-side filtering, sorting, pagination, search, export, and URL state sync. | [Link](https://github.com/jacksonkasi1/TableCraft) | 2026-02-27 |
| tanstack-ui-table | Customizable table with @tanstack/table and shadcn/ui | [Link](https://github.com/drefahl/tanstack-ui-table) | 2025-02-27 |
| the-gridcn | Tron inspired shadcn/ui theme | [Link](https://thegridcn.com/) | 2026-02-06 |
| time-picker | Simple TimePicker component. | [Link](https://github.com/openstatusHQ/time-picker) | 2024-04-29 |
| tnks-data-table | Advanced data table component built with shadcn/ui and TanStack Table featuring server-side operations, row selection, filtering, column customization, and export functionality. Fully TypeScript compatible with comprehensive documentation. | [Link](https://github.com/jacksonkasi1/tnks-data-table) | 2025-04-19 |
| tool-ui | Beautiful, ready-to-use UI components for AI tool calls and MCP UI. | [Link](https://www.tool-ui.com/) | 2025-12-10 |
| tour | A component for building onboarding tours. Designed to integrate with shadcn/ui. | [Link](https://onboarding-tour.vercel.app) | 2025-12-04 |
| tremor | Components for charts and dashboards. | [Link](https://github.com/tremorlabs/tremor) | 2024-06-15 |
| twblocks | Website blocks based on shadcn & Radix. | [Link](https://github.com/tommyjepsen/twblocks) | 2024-11-25 |
| tweet-to-code | Twitter design recreations as code. | [Link](https://tweet-to-code.vercel.app/) | 2024-12-26 |
| ui-beats | Animated React Components collection. | [Link](https://uibeats.com) | 2024-09-23 |
| ui-layouts | UI Layouts isn’t just a library. It’s a complete toolkit with components, effects, design tools, and ready-to-use blocks, everything you need to build modern interfaces, faster. | [Link](https://www.ui-layouts.com/) | 2025-10-15 |
| ui-nference-sh | a shadcn registry of react ui components for building ai-powered applications, chatbots, and ai agent interfaces. | [Link](https://ui.inference.sh/) | 2026-02-13 |
| uixmat-onborda | Product tour for Next.js applications. | [Link](https://github.com/uixmat/onborda) | 2024-06-07 |
| uselayouts | Free premium animated React components and micro-interactions built with Framer Motion and Tailwind CSS. Modern, ready-to-use motion components for high-converting websites. | [Link](https://uselayouts.com) | 2026-01-23 |
| vaul | Drawer component for React. | [Link](https://vaul.emilkowal.ski/) | 2024-06-07 |
| vengence-ui | A modern, animated UI component library designed to help developers build beautiful landing pages and interfaces faster. | [Link](https://www.vengenceui.com/) | 2026-02-17 |
| vyoma-ui | Beautiful Components Made on top of Shadcn/ui with Spatial Wisdom Inside. Truly Beyond UI. | [Link](https://vyomaui.design/) | 2025-07-15 |
| warcraftcn | A set of components inspired by classic Warcraft III RTS UI aesthetics | [Link](https://www.warcraftcn.com/) | 2026-02-06 |
| wds registry | A collection of components that you can use to build your own component library. | [Link](https://wds-shadcn-registry.netlify.app) | 2025-09-06 |
| zoom-charts | Zoomable Charts with shadcn/ui. | [Link](https://github.com/shelwinsunga/zoom-chart-demo) | 2024-07-16 |
## Registries
| Name | Description | Link | Date |
| ------------------ | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | ---------- |
| efferd | ready-to-use shadcn blocks that just work — modern, responsive, and built for speed. | [Link](http://efferd.com/) | 2026-03-05 |
| more-shadcn | A collection of high-quality, copy-paste components for Svelte 5, built on top of shadcn-svelte. | [Link](https://more-shadcn.noair.fun/) | 2026-01-23 |
| neobrutalism-vue | A vue-based registry of neobrutalism-styled Tailwind components. | [Link](https://github.com/michaelsieminski/neobrutalism-vue) | 2025-12-04 |
| registry.directory | A curated directory to discover, preview, and copy shadcn/ui registries. | [Link](https://github.com/rbadillap/registry.directory) | 2025-09-20 |
| tailark | Shadcn blocks for building modern marketing websites | [Link](https://tailark.com) | 2026-02-06 |
| undraw-cn | Beautiful, customizable React components for unDraw illustrations. | [Link](https://undraw-cn.vaatun.com) | 2025-12-04 |
## Plugins and Extensions
| Name | Description | Link | Date |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | ---------- |
| chat-with-youtube | A chrome extension is designed to give you the ability to efficiently summarize videos, easily search for specific parts, and enjoy additional useful features. | [Link](https://chat-with-youtube.vercel.app/) | 2024-06-07 |
| designgui | A Chrome Browser Extension for managing colors in CSS Variables. | [Link](https://www.designgui.io/) | 2024-09-05 |
| imprompt | A Chrome extension that enhances prompts on AI websites directly, making your AI prompts more effective and productive. | [Link](https://github.com/avalynndev/imprompt) | 2025-09-06 |
| raycast-shadcn | Raycast extension to Browse shadcn/ui documentation, components, and examples. | [Link](https://www.raycast.com/luisFilipePT/shadcn-ui) | 2024-06-05 |
| shadcn-hsl-preview | shadcn HSL Preview extension for Visual Studio Code. | [Link](https://marketplace.visualstudio.com/items?itemName=dexxiez.shadcn-color-preview) | 2024-09-05 |
| shadcn-ui | Add components from shadcn/ui directly from VS Code. | [Link](https://marketplace.visualstudio.com/items?itemName=SuhelMakkad.shadcn-ui) | 2024-03-08 |
| shadcn/ui Components Manager | A plugin for Jetbrain products. It allows you to manage your shadcn/ui components across Svelte, React, Vue, and Solid frameworks with this plugin. Simplify tasks like adding, removing, and updating components. | [Link](https://plugins.jetbrains.com/plugin/23479-shadcn-ui-components-manager) | 2024-03-28 |
| vscode-shadcn-svelte | VS Code extension for shadcn/ui components in Svelte projects. | [Link](https://marketplace.visualstudio.com/items?itemName=Selemondev.vscode-shadcn-svelte&ssr=false#overview) | 2024-03-28 |
| vscode-shadcn-ui-snippets | Easily import and use shadcn-ui components with ease using snippets within VSCode. Just type cn or shadcn in your jsx/tsx file and you will get a list of all the components to choose from. | [Link](https://marketplace.visualstudio.com/items?itemName=VeroXyle.shadcn-ui-snippets) | 2024-06-05 |
| vscode-shadcn-vue | Extension for integrating shadcn/ui components into Vue.js projects. | [Link](https://marketplace.visualstudio.com/items?itemName=Selemondev.shadcn-vue) | 2024-03-28 |
## Colors and Customizations
| Name | Description | Link | Date |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------- |
| 10000+Themes for shadcn/ui | 10000+ Themes for shadcn/ui. | [Link](https://ui.jln.dev/) | 2024-02-22 |
| dizzy | Bootstrap a new Next or Vite project with shadcn/ui. Customize font, icons, colors, spacing, radii, and shadows. | [Link](https://dizzy.systems) | 2024-06-05 |
| ewgenius/ui | Create custom themes for shadcn/ui effortlessly using vibrant palettes from Radix Colors. | [Link](https://ui.ewgenius.me/shadcn-radix-colors) | 2024-10-11 |
| gradient-picker | Fancy Gradient Picker built with shadcn/ui, Radix UI, and Tailwind CSS. | [Link](https://github.com/Illyism/gradient-picker) | 2024-03-08 |
| navnote/rangeen | Tool that helps you to create a colour palette for your website. | [Link](https://github.com/navnote/rangeen) | 2024-06-05 |
| shadesigner.com | A shadcn/ui Palette Generator & Theme Designer with a beautiful interface. | [Link](https://shadesigner.com) | 2024-12-26 |
| shadcn-ui-customizer | POC - shadcn/ui themes with color pickers. | [Link](https://github.com/Railly/shadcn-ui-customizer) | 2024-03-08 |
| shadcn theme editor | Shadcn Theme Editor is a user-friendly component designed to simplify the process of managing and customizing theme colors in Shadcn-based projects. | [Link](https://github.com/programming-with-ia/shadcn-theme-editor/) | 2024-08-19 |
| smui | Nord-inspired terminal theme for shadcn/ui with monospace typography, zero border radius, and frost-blue accents. | [Link](https://smui.statico.io) | 2026-02-18 |
| tweakcn | powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS V4 integration | [Link](https://tweakcn.com/) | 2025-03-25 |
| ui-colorgen | An application designed to assist you with color configuration of shadcn/ui. | [Link](https://ui-colorgen.vercel.app/) | 2024-02-22 |
| zippy starter's shadcn/ui theme generator | Easily create custom themes from a single colour that you can copy and paste into your apps. | [Link](https://zippystarter.com/tools/shadcn-ui-theme-generator) | 2024-03-13 |
## Animations
| Name | Description | Link | Date |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | ---------- |
| animata | Hand-crafted ✍️ interaction animations and effects from around the internet 🛜 to copy and paste into your project. | [Link](https://animata.design) | 2024-08-26 |
| animate-ui | A fully animated, open-source React component distribution. Browse a list of animated primitives, components and icons you can install and use in your projects. | [Link](https://animate-ui.com/) | 2025-10-15 |
| magicui.design | Largest collection of open-source react components to build beautiful landing pages. | [Link](https://magicui.design) | 2024-04-25 |
| motionvariants | Beautiful Framer Motion Animations. | [Link](https://github.com/chrisabdo/motionvariants) | 2024-03-08 |
| smooth-ui | Highly customizable, production-ready UI blocks for building beautiful websites and apps that look and feel the way you mean it. | [Link](https://smoothui.dev/) | 2025-10-15 |
| tailwindcss-motion | A new simple syntax animation library. Batteries included. Infinitely configurable. | [Link](https://rombo.co/tailwind/) | 2024-11-13 |
## Tools
| Name | Description | Link | Date |
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ---------- |
| 5devs | A website to get fake Brazilian data for testing purposes. | [Link](https://www.5devs.com.br/) | 2024-05-31 |
| bento-hub | BentoHub is an application where you can create a bento grid for your GitHub profile readme. | [Link](https://github.com/amittam104/BentoHub) | 2024-09-09 |
| cheatsheet | A comprehensive, interactive reference for shadcn/ui components with live previews, code examples, and instant copy functionality. | [Link](https://shadcnstore.com/cheatsheet/) | 2025-09-22 |
| cut-it | Link shortener built using Next.js App Router, Server Actions, Drizzle ORM, Turso, and styled with shadcn/ui. | [Link](https://github.com/mehrabmp/cut-it) | 2024-06-07 |
| country-data-in-charts | Globe Graph is a web app that visualizes countries' data like GDP, GDP per capita, and population in different years using many charts. | [Link](https://globe-graph.vercel.app/) | 2024-09-09 |
| dev-quotes | A website that displays quotes from professional programmers. | [Link](https://dev-quotes-six.vercel.app/) | 2025-01-07 |
| down-dev-detector | This app lists all the services currently down and uses Atlassian Status Page and others (soon). | [Link](https://github.com/birobirobiro/downdevdetector) | 2024-11-04 |
| cv-forge | Resume builder built with @shadcn/ui, react-hook-form, and react-pdf. | [Link](https://cvforge.app) | 2024-11-04 |
| focus-brew | A free productivity toolkit that combines essential tools to help you stay focused, organized, and efficient throughout your workday. | [Link](https://focusbrew.vercel.app) | 2025-05-14 |
| form-builder | UI-based codegen tool to easily create beautiful and type-safe @shadcn/ui forms. | [Link](https://github.com/AlandSleman/FormBuilder) | 2024-06-07 |
| form-builder-fast | Shadcn Form Builder - Build forms in minutes for free. | [Link](https://ui.indie-starter.dev/form-builder) | 2024-12-26 |
| graphitup | Create free downloadable Shadcn-themed chart images. Supports PNG, JPEG, WEBP, and even WEBM videos. Upload your own data for more realistic designs. | [Link](https://graphitup.com/tools) | 2025-12-26 |
| hook-again | A collection of shadcn/ui installable React Hooks. | [Link](https://github.com/ilyichv/hookagain) | 2024-11-04 |
| Img2m3 | A developer tool that automates the process of creating cohesive, accessible design systems. It bridges the gap between Google's Material Design 3 algorithms and the modern Tailwind CSS v4 ecosystem. | [Link](https://img2m3.vercel.app/studio) | 2026-01-23 |
| imgsrc | Generate beautiful Open Graph images with zero effort. | [Link](https://imgsrc.io/) | 2024-05-31 |
| invoify | An invoice generator app built using Next.js, TypeScript, and shadcn/ui. | [Link](https://github.com/aliabb01/invoify) | 2024-03-27 |
| jobsync | JobSync is a job seekers' assistant to manage job search efficiently. | [Link](https://github.com/Gsync/jobsync) | 2024-07-17 |
| memfree | Open-source hybrid AI search engine, instantly get accurate answers from the internet, bookmarks, notes, and docs. Built using Next.js and shadcn/ui. | [Link](https://github.com/memfreeme/memfree) | 2024-07-22 |
| opensearch-ai | SearchGPT/Perplexity clone but personalized for you. | [Link](https://github.com/supermemoryai/opensearch-ai) | 2024-12-26 |
| pagegen.ai | An AI Page Generator with Claude AI, React, and shadcn/ui. Generate web pages from text, screenshots, and templates with one click. | [Link](https://pagegen.ai) | 2024-12-26 |
| pastecode | Pastebin alternative built with TypeScript, Next.js, Drizzle, shadcn/ui, and RSC. | [Link](https://github.com/Quorin/PasteCode.app) | 2024-06-07 |
| pictera | Generate Open Graph images without design skills. | [Link](https://pictera.co) | 2025-10-08 |
| proxmox-helper-scripts | A catalog of scripts for your Proxmox VE homelab, built with the Next.js App Router and styled with shadcn/ui. | [Link](https://github.com/BramSuurdje/proxmox-helper-scripts) | 2024-07-16 |
| quack-db | Open-source in-browser DuckDB SQL editor. | [Link](https://github.com/mattf96s/QuackDB) | 2024-10-03 |
| shadcn-easy-install | Install all shadcn components easily. One-click to install all selected components. | [Link](https://shadcn-easy-install.vercel.app/) | 2025-06-10 |
| shadcn-form-builder | Create forms with Shadcn, react-hook-form, and Zod within minutes. | [Link](https://shadcn-form-build.vercel.app/) | 2024-10-03 |
| shadcn-hooks | A comprehensive React Hooks Collection built with Shadcn. | [Link](https://shadcn-hooks.com/) | 2025-10-13 |
| shadcn-play | A playground for building and previewing shadcn/ui components with a live editor. | [Link](https://github.com/ephraimduncan/shadcn-play) | 2026-02-13 |
| shadcn-pricing-page-generator | The easiest way to get a React pricing page with shadcn/ui, Radix UI, and/or Tailwind CSS. | [Link](https://shipixen.com/shadcn-pricing-page) | 2024-03-08 |
| shadcn-theme-editor | Shadcn Theme Editor is a user-friendly component designed to simplify the process of managing and customizing theme colors in Shadcn-based projects. | [Link](https://shadcnthemeeditor.vercel.app) | 2024-08-19 |
| shadcn-zod-form | CLI tool to generate shadcn/ui forms from Zod schemas. | [Link](https://github.com/ilyichv/shadcn-zod-form) | 2024-10-03 |
| sharable-form-builder | A sharable form builder for creating forms and sharing your form link, based on shadcn/ui and Next.js. | [Link](https://github.com/ayoubben18/sharable-form-builder) | 2024-10-12 |
| shoogle | A shadcn search engine | [Link](https://shoogle.dev/) | 2026-02-13 |
| slidytabs | A tool that adds a sliding indicator animation to shadcn `` without changing how you use or customize the component | [Link](https://slidytabs.dev) | 2026-01-23 |
| someday | Free to host and open-source Cal.com/Calendly alternative built on Google Apps Script for Gmail users. | [Link](https://github.com/rbbydotdev/someday) | 2024-12-26 |
| sweep | Sweep is a modern, open-source gradient generator built for designers and developers. Create beautiful linear and radial gradients with real-time preview, noise/blur effects, and export to CSS, Tailwind, SVG, or JPG. Free forever. No sign-up required. | [Link](https://github.com/Johuniq/sweep) | 2025-11-11 |
| tancn | Build powerful forms and tables with ease using TanStack technologies | [Link](https://tancn.dev/) | 2025-11-02 |
| tinte | An opinionated VS Code Theme Generator 🎨. | [Link](https://tinte.railly.dev/) | 2024-10-03 |
| translate-app | Translate App using TypeScript, Tailwind CSS, NextJS, Bun, shadcn/ui, AI SDK/OpenAI, and Zod. | [Link](https://github.com/developaul/translate-app) | 2024-07-08 |
| typelabs | MonkeyType-inspired typing test app built with React, shadcn, and Zustand at its core. | [Link](https://github.com/imsandeshpandey/typelabs) | 2024-07-08 |
| ui-builder | A React component editor that provides a no-code, visual way to create UIs, fully compatible with shadcn/ui and custom components. | [Link](https://github.com/olliethedev/ui-builder) | 2024-10-11 |
| ui-fonts | Test and preview fonts in real-time for all your design needs. Choose the perfect typeface with ease. | [Link](https://www.uifonts.app/) | 2024-10-23 |
| v0 | Vercel's generative UI system, built on shadcn/ui and TailwindCSS, allows effortless UI generation from text prompts and/or images. | [Link](https://v0.dev/) | 2024-03-27 |
| vercel-status-tracker | Track the status of all of your projects deployed via Vercel. Built with shadcn/ui and TailwindCSS. | [Link](https://vercel-status-tracker.vercel.app) | 2025-01-02 |
| wallhaven-desktop | Wallhaven Wallpaper software desktop. Create a Wallhaven API-based client, a true wallpaper software. | [Link](https://github.com/ErKeLost/wallhaven-desktop) | 2024-10-23 |
## Websites and Portfolios
| Name | Description | Link | Date |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | ---------- |
| andrewsam.xyz | A revamped version of the popular tailwind-nextjs-starter-blog using shadcn/ui, along with a resume section and experience timeline component. | [Link](https://www.andrewsam.xyz/) | 2024-09-18 |
| anishshobithps.com | Personal portfolio of a software developer, grid-styled design . | [Link](https://anishshobithps.com/) | 2026-02-27 |
| birobirobiro.dev | A personal developer portfolio. | [Link](https://birobirobiro.dev/) | 2024-07-29 |
| bucharitesh.in | A minimal portfolio with awesome craft's registry. | [Link](https://bucharitesh.in) | 2025-12-25 |
| chanhdai.com | A minimal portfolio, component registry, and blog. | [Link](https://chanhdai.com) | 2025-09-11 |
| devfolios | Find best portfolio inspiration from all over the internet | [Link](https://devfolios-one.vercel.app/) | 2025-10-25 |
| godly | Astronomically good web design inspiration. Only the best of the best. | [Link](https://godly.website/) | 2024-07-29 |
| hritu.art | A clean, modern designer portfolio blending minimal aesthetics with functional UI and built-in email support via React Email. | [Link](https://github.com/suraj-xd/design-portfolio) | 2025-06-10 |
| kinhdev24 | Developer portfolio built with Next.js, shadcn/ui, Aceternity, and Magic UI | [Link](https://kinhdev.id.vn/) | 2025-07-08 |
| list.swajp.me | It has never been easier to find the right projects or designs by inspiring successful people. | [Link](https://list.swajp.me) | 2024-07-29 |
| mpakravan | Portfolio website using React, Next.js, Tailwind CSS, ShadCN, and GSAP, modern design system. | [Link](https://mpakravan.com/en) | 2025-10-26 |
| nathans-ai | An AI Chatbot acting as a portfolio, built with shadcn/ui components. | [Link](https://chat.brodin.dev) | 2024-11-21 |
| ifte-13 | Portfolio made with Next.js, shadcn/ui (with magic ui ) and Email.js | [Link](https://ifte-13.vercel.app/) | 2025-10-25 |
| shubhporwal.me | An eye-catching developer portfolio, built on NextJS, GSAP, Tailwind, and React. | [Link](https://www.shubhporwal.me/) | 2024-10-03 |
| swajp.me | A visually appealing portfolio and resource hub. | [Link](https://swajp.me) | 2024-07-29 |
| windows-11-clone | A sleek Windows 11 clone built with React, Next.js, Tailwind CSS, ShadCN, and Framer-Motion, featuring smooth animations, draggable windows, and a modern design system. | [Link](https://win11.oimmi.com/) | 2025-02-20 |
## Platforms
| Name | Description | Link | Date |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ---------- |
| anonypost | Share your thoughts and experiences anonymously by posting on the platform. Crafted using t3-stack. | [Link](https://github.com/avalynndev/anonypost) | 2024-07-17 |
| bolhadev | The quickest path to learn English is speaking it regularly. Just find someone to chat with. | [Link](https://bolhadev.chat/) | 2024-06-04 |
| citeme | AI-powered academic citation generator. Searches 11+ databases and formats in 40+ styles (APA, ABNT, MLA, etc.). Web app, Chrome extension, Google Docs add-on, and Word add-in. | [Link](https://citeme.app) | 2026-03-03 |
| enjoytown | A free anime, manga, movie, and TV-shows streaming platform. Built with Next.js, shadcn/ui. | [Link](https://github.com/avalynndev/enjoytown) | 2024-06-04 |
| grade-calculator | A grade calculator/dashboard for students, aiming to provide a better overview of academic performance. | [Link](https://grades.nstr.dev/) | 2024-12-27 |
| infinitunes | A simple music player web app built using Next.js, shadcn/ui, Tailwind CSS, Drizzle ORM, and more. | [Link](https://github.com/rajput-hemant/infinitunes) | 2024-06-04 |
| kd | Ad-free Kdrama streaming app. Built with Next.js, Drizzle ORM, NeonDB, and shadcn/ui. | [Link](https://github.com/gneiru/kd) | 2024-05-31 |
| memergez | Quickly generate memes by entering text or an avatar URL, with support for many meme commands. | [Link](https://github.com/avalynndev/memergez) | 2024-08-26 |
| midday-components | A collection of open-source components based on Midday features. | [Link](https://midday.ai/components) | 2024-11-21 |
| multiboard | Minimal Kanban platform. Built with Better-Auth, Next.js, ZenStack, Prisma, and shadcn/ui. | [Link](https://github.com/olliethedev/multiboard) | 2025-07-15 |
| openhive | Open-source, self-hosted Slack alternative with channels, DMs, threads, reactions, file uploads, and video/audio calls. Built with Next.js, Supabase, Zustand, and shadcn/ui. | [Link](https://github.com/arseneHuot/openhive) | 2026-03-14 |
| plotwist | Easy management and reviews of your movies, series, and animes using Next.js, Tailwind CSS, Supabase, and shadcn/ui. | [Link](https://plotwist.app/en-US) | 2024-05-31 |
| snapimg | Fast, privacy-focused image compression tool supporting PNG, JPEG, WebP, AVIF. Built with React 19, Vite, Tailwind CSS, and shadcn/ui. | [Link](https://github.com/Moresl/snapimg) | 2025-12-15 |
| veritas-kanban | Self-hosted Kanban board with AI agent integration, time tracking, and 1,255 tests. Built with React 19, Vite 6, TanStack Query, dnd-kit, and shadcn/ui. | [Link](https://github.com/BradGroux/veritas-kanban) | 2026-01-29 |
| xeramail | Temporary email address service built with Next.js and shadcn/ui, offering fast inbox access, modern UI, and better control over disposable emails. | [Link](https://xeramail.com) | 2026-01-01 |
| youropinion.is | Free survey platform which supports importing your exisitng shadcn/ui theme | [Link](https://youropinion.is/news/202505-match-my-style) | 2025-06-16 |
## Ports
| Name | Description | Link | Date |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ---------- |
| Angular | Angular port of shadcn/ui. | [Link](https://github.com/goetzrobin/spartan) | 2024-03-21 |
| Basecoat | Vanilla HTML, CSS and JS port of shadcn/ui. | [Link](https://basecoatui.com) | 2025-07-07 |
| Flutter | Flutter port of shadcn/ui. | [Link](https://github.com/nank1ro/shadcn-ui) | 2024-06-07 |
| Franken UI | HTML-first, framework-agnostic, beautifully designed components that you can truly copy and paste into your site. Accessible. Customizable. Open Source. | [Link](https://www.franken-ui.dev/) | 2024-06-07 |
| JollyUI | shadcn/ui compatible react aria components. | [Link](https://github.com/jolbol1/jolly-ui) | 2024-06-07 |
| Kotlin | Kotlin port of shadcn/ui. | [Link](https://github.com/dead8309/shadcn-kotlin) | 2024-06-07 |
| mkdocs-shadcn | MkDocs port of shadcn/ui. | [Link](https://github.com/asiffer/mkdocs-shadcn) | 2025-07-07 |
| .NET (ShadUI) | Avalonia port of shadcn/ui. Based on SukiUI | [Link](https://github.com/accntech/shad-ui/) | 2024-02-22 |
| Phoenix Liveview | Phoenix Liveview port of shadcn/ui. | [Link](https://github.com/bluzky/salad_ui) | 2024-06-07 |
| React Native | React Native port of shadcn/ui. | [Link](https://github.com/Mobilecn-UI/nativecn-ui) | 2024-06-07 |
| React Native (recommended) | React Native port of shadcn/ui (recommended). | [Link](https://github.com/mrzachnugent/react-native-reusables) | 2024-12-27 |
| Ruby | Ruby port of shadcn/ui. | [Link](https://github.com/aviflombaum/shadcn-rails) | 2024-06-07 |
| Solid | Solid port of shadcn/ui. | [Link](https://github.com/hngngn/shadcn-solid) | 2024-03-28 |
| Svelte | Svelte port of shadcn/ui. | [Link](https://github.com/huntabyte/shadcn-svelte) | 2024-02-22 |
| Swift | Swift port of shadcn/ui. | [Link](https://github.com/Mobilecn-UI/swiftcn-ui) | 2024-06-07 |
| Sysinfocus simple/ui | Razor component library for Blazor, inspired by shadcn/ui. | [Link](https://sysinfocus.github.io/shadcn-inspired/) | 2024-09-09 |
| Vue | Vue port of shadcn/ui. | [Link](https://github.com/radix-vue/shadcn-vue) | 2024-02-22 |
## Design System
| Name | Description | Link | Date |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ---------- |
| shadcn-storybook-registry | Registry of stories for the shadcn components. Quickly get the atomic level components documented in Storybook. | [Link](https://registry.lloydrichards.dev/) | 2025-02-07 |
| obra-shadcn-ui | This file replicates all 51 shadcn/ui v4 components in a composable way as a reusable Figma library.. | [Link](https://www.figma.com/community/file/1514746685758799870/obra-shadcn-ui) | 2025-06-16 |
| shadcn-ui-components | Every component recreated in Figma. | [Link](https://www.figma.com/community/file/1342715840824755935/shadcn-ui-components) | 2024-03-21 |
| shadcn-ui-storybook (JheanAntunes) | All shadcn/ui components registered in the storybook by JheanAntunes. | [Link](https://65711ecf32bae758b457ae34-uryqbzvojc.chromatic.com/) | 2024-12-27 |
| shadcn-ui-storybook (fellipeutaka) | All shadcn/ui components registered in the storybook by fellipeutaka. | [Link](https://fellipeutaka-ui.vercel.app/?path=/docs/components-accordion--docs) | 2024-12-27 |
## Boilerplates / Templates
| Name | Description | Link | Date |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| agentic-react-nextjs-shadcn | Agent-testable SaaS starter built with Next.js 16, shadcn/ui, and Tailwind CSS. Includes accessibility-first components, semantic HTML for AI agent testing, and production-ready patterns. | [Link](https://github.com/iscale-llc/agentic-react-nextjs-shadcn) | 2026-03-03 |
| astro-erudite | An opinionated, unstyled static blogging template—built with Astro, Tailwind, and shadcn/ui. | [Link](https://github.com/jktrn/astro-erudite) | 2025-10-25 |
| atomic-crm | Open-source React CRM built on top of Supabase [Demo site](https://marmelab.com/atomic-crm-demo) | [Link](https://github.com/marmelab/atomic-crm) | 2025-09-16 |
| autoflow | An open source GraphRAG (Knowledge Graph) built on top of TiDB Vector, LlamaIndex, and DSPy. [Demo site](https://tidb.ai). | [Link](https://github.com/pingcap/autoflow) | 2024-12-06 |
| browser-extension-starter-plasmo-shadcn-trpc | Browser extension starter kit featuring Plasmo, React, Shadcn, and tRPC. | [Link](https://github.com/poweroutlet2/browser-extension-starter-plasmo-shadcn-trpc) | 2024-10-29 |
| chadnext | Quick Starter Template includes Next.js 14 App Router, shadcn/ui, LuciaAuth, Prisma, Server Actions, Stripe, Internationalization, and more. | [Link](https://github.com/moinulmoin/chadnext) | 2024-04-25 |
| cloudflare-saas-stack | An opinionated, batteries-included starter kit for quickly building and deploying SaaS products on Cloudflare. | [Link](https://github.com/Dhravya/cloudflare-saas-stack) | 2024-07-24 |
| create-tauri-core | A project template for creating a Tauri app with Vite, React, and Tailwind CSS. | [Link](https://github.com/mrlightful/create-tauri-core) | 2024-09-23 |
| design-system-template | Turborepo + TailwindCSS + Storybook + shadcn/ui. | [Link](https://github.com/arevalolance/design-system-template) | 2024-06-06 |
| devstarter | Devstarter is a bold, one-page developer portfolio template with a distinctive cyberpunk aesthetic. Built with Next.js, shadcn/ui, and Tailwind CSS, it's designed to help developers showcase their work, skills, and personality in a way that stands out. | [Link](https://github.com/zippystarter/template-devstarter) | 2026-01-27 |
| easy-ui | 50+ High Quality Open Source Website Templates built using NextJS + shadcn/ui + Tailwind CSS + Framer Motion and more. | [Link](https://github.com/DarkInventor/easy-ui) | 2024-08-06 |
| ecommerce-kit | Next.js starter kit with the tools you need to quickly launch your e-commerce site. | [Link](https://ecommercekit.dev) | 2025-09-06 |
| electron-shadcn | Electron app template with shadcn/ui and a bunch of other libs and tools ready to use. | [Link](https://github.com/LuanRoger/electron-shadcn) | 2024-06-17 |
| forjnot | Modern Project Starter Kit | Launch your next project faster with Forjnot - A professional, customizable and clean starting point featuring modern tech stack and best practices | 2025-11-20 |
| full-stack-monorepo-starter | Full stack monorepo template built using shadcn/ui + Fastify + graphql + vitejs + Docker and more. | [Link](https://github.com/mnove/monorepo-starter-graphql) | 2025-06-10 |
| fumadocs-starter | A fully-fledged Fumadocs starter template with built-in plugins, AI features, and everything you need to build your next docs site. | [Link](https://github.com/techwithanirudh/fumadocs-starter) | 2025-11-20 |
| horizon-ai-nextjs-shadcn-boilerplate | Premium AI NextJS & shadcn/ui Boilerplate + Stripe + Supabase + OAuth. | [Link](https://horizon-ui.com/boilerplate-shadcn) | 2024-05-24 |
| kirimase | A template and boilerplate for quickly starting your next project with shadcn/ui, Tailwind CSS, and Next.js. | [Link](https://kirimase.dev/) | 2024-06-11 |
| login-auth | A login authentication web app built with Vite + React, Tailwind CSS, and Shadcn UI. It uses Firebase for Google sign-in, email sign-up, and password reset. | [Link](https://shadcn-login-auth.vercel.app/) | 2026-03-15 |
| magicui-startup-templates | Magic UI Startup template built using shadcn/ui + TailwindCSS + Framer Motion. | [Link](https://magicui.design/docs/templates/startup) | 2024-04-25 |
| next-shadcn-admin-dashboard | Modern Admin Dashboard Template built with Shadcn UI and Next.js 15 | [Link](https://github.com/arhamkhnz/next-shadcn-admin-dashboard) | 2025-10-25 |
| nextMotion | Webdev portfolio template with Nodemailer integrated for easy contact form setup. Uses shadcn/ui + TailwindCSS + Framer Motion. | [Link](https://github.com/yoyocharlie/nextMotion) | 2024-09-23 |
| next-js-boilerplate | Quickly set up a Next.js project with TypeScript, NextAuth.js, PostgreSQL (Prisma), Sentry, Tailwind CSS v4, shadcn/ui, Zod, Zustand, nuqs, ESLint, Husky, and Prettier. [Demo site](https://next-js-boilerplate-sage-nine.vercel.app/). | [Link](https://github.com/AbhishekSharma55/next-js-boilerplate) | 2025-09-08 |
| next-shadcn-dashboard-starter | Admin Dashboard Starter with Nextjs 14 and shadcn/ui. | [Link](https://github.com/Kiranism/next-shadcn-dashboard-starter) | 2024-06-06 |
| next-starter | A Next.js starter template packed with features like TypeScript, TailwindCSS, Next-auth, Eslint, Stripe, testing tools, and more. Jumpstart your project with efficiency and style. | [Link](https://github.com/Skolaczk/next-starter) | 2024-09-23 |
| nextjs-mdx-blog | Starter template built with Contentlayer, MDX, shadcn/ui, and Tailwind CSS. | [Link](https://github.com/ChangoMan/nextjs-mdx-blog) | 2024-04-25 |
| next-js-views-template | An open-source collection of reusable view components like Calendar, Table, etc., built with Next.js and ShadCN. Easily copy and paste these pre-built UI elements into your project for fast, responsive, and customizable layouts. | [Link](https://next-js-views-template.vercel.app) | 2024-11-21 |
| next-wp | Headless Wordpress Starter built with the NextJS App Router and React Server Components. | [Link](https://github.com/9d8dev/next-wp) | 2024-11-21 |
| onyx | Full stack, batteries-included MVP Template with NextJS 14, Supabase SSR Auth & Postgres DB with CRUD operations, RBAC, Tanstack React Query, Zod Validation, MDX components, Resend, and more. | [Link](https://github.com/rmourey26/onyx) | 2024-08-13 |
| opendocs | Beautifully designed template that you can use for your projects for free. Accessible. Customizable. Open Source with i18n support. | [Link](https://opendocs.daltonmenezes.com/) | 2024-07-29 |
| react-starter-kit | An opinionated, full-stack boilerplate for building modern web apps on the edge. Features Bun, React 19, tRPC, Drizzle ORM, and Cloudflare Workers. | [Link](https://github.com/kriasoft/react-starter-kit) | 2025-09-06 |
| react-vite-starter | React starter powered with Vite + Redux Toolkit + RTKQuery + React Router + shadcn UI and many more. | [Link](https://github.com/tejachundru/react-vite-starter) | 2024-12-02 |
| shadcn-admin | A admin dashboard template for Next.js, React, Vite and Vue.js, built with Tailwind CSS. | [Link](https://shadcnadmin.com) | 2025-12-12 |
| shadcn-landing-page | Landing page template using shadcn/ui, React, TypeScript, and Tailwind CSS. | [Link](https://github.com/leoMirandaa/shadcn-landing-page) | 2024-06-06 |
| shadcn-landing-page (Vue) | Project conversion [shadcn-vue-landing-page](https://github.com/leoMirandaa/shadcn-vue-landing-page) to Next.js - Landing page template using Nestjs, shadcn/ui, TypeScript, and Tailwind CSS. | [Link](https://github.com/nobruf/shadcn-landing-page) | 2024-12-27 |
| shadcn-nextjs-free-boilerplate | Free & Open-source NextJS Boilerplate + ChatGPT API Dashboard Template. | [Link](https://github.com/horizon-ui/shadcn-nextjs-boilerplate) | 2024-05-24 |
| shadcn-nextjs-dashboard | Admin Dashboard UI built with Shadcn and NextJS. Free and Open-source. | [Link](https://github.com/NaveenDA/shadcn-nextjs-dashboard) | 2025-06-22 |
| shadcn-portfolio | A portfolio template, which uses shadcn-ui and Next.JS. | [Link](https://github.com/techwithanirudh/shadcn-portfolio) | 2025-11-20 |
| shadcn-registry-template | Template repository for building a custom component registry for shadcn/ui. | [Link](https://github.com/vantezzen/shadcn-registry-template) | 2024-09-05 |
| shadcn-saas-landing | A full-fledged SaaS Landing template built using Next.JS, shadcn/ui, and fumadocs. | [Link](https://github.com/techwithanirudh/shadcn-saas-landing) | 2025-11-20 |
| shadcn-ui-dashboard | Multipurpose and powerful admin dashboard template compatible with shadcn/ui. | [Link](https://shadcnuidashboard.com) | 2025-09-21 |
| shadcn-vue-landing-page | Landing page template using Vue, shadcn-vue, TypeScript, and Tailwind CSS. | [Link](https://github.com/leoMirandaa/shadcn-vue-landing-page) | 2024-06-06 |
| shadcn-next-workflows | Interactive workflow builder using React Flows, Next.js, and Shadcn/ui. Create, connect, and validate custom nodes easily. | [Link](https://github.com/nobruf/shadcn-next-workflows) | 2024-10-29 |
| supa-next-shad-auth | A fully responsive, fully type-safe, secure server actions, user-friendly customizable UI with best practices. Tech used: NextJS + Supabase + TypeScript + Server Actions + Zod + shadcn/ui. | [Link](https://github.com/Sahil-Sharma-23/supa-next-shad-auth) | 2024-07-02 |
| sveltekit-shadcn-starter-kit | Production ready open-source generic app template featuring database abstraction (Drizzle & Postgres), server utilities, tests, authentication (better-auth), i18n + RTL/LTR support, mdsvex, predefined pages and content (policies, legal, etc.), App Shell component, base and custom components built with shadcn/ui, Cookies management (compliance), SEO managemnt support, CLI tooling and more. [Demo](https://ssv5.templates.guylahav.com) | [Link](https://github.com/GantonL/templates/tree/main/sveltekit-shadcn-v5) | 2025-09-23 |
| t3-app-template | Admin template for T3 Stack and shadcn/ui. | [Link](https://github.com/gaofubin/t3-app-template) | 2024-04-25 |
| tailwind-admin | Open Source Shadcn Dashboard Template Built On React and Tailwind CSS | [Link](https://github.com/Tailwind-Admin/free-tailwind-admin-dashboard-template) | 2026-01-03 |
| taxonomy | An open-source application built using the new router, server components, and everything new in Next.js. | [Link](https://github.com/shadcn/taxonomy) | 2024-03-21 |
| template-next | A clean Next.js template with TypeScript, TailwindCSS, Shadcn/ui, and Prettier. | [Link](https://template-next-official.vercel.app/) | 2024-09-24 |
| turborepo-nextjs-wxt-shadcn-boilerplate | Turborepo boilerplate featuring web and web-extension apps with shadcn/ui for shared ui components and unified Typescript, ESLint, Tailwind CSS, and Prettier configs. | [Link](https://github.com/Aniket-508/turborepo-nextjs-wxt-shadcn-boilerplate) | 2025-04-24 |
| turborepo-shadcn-ui-tailwindcss | Turborepo starter with shadcn/ui & TailwindCSS pre-configured for shared UI components. | [Link](https://github.com/henriqpohl/turborepo-shadcn-ui-tailwindcss) | 2024-06-06 |
| turborepo-launchpad | A comprehensive monorepo boilerplate for shadcn projects using Turbo. It features a highly scalable setup ideal for developing complex applications with shared components and utilities. | [Link](https://github.com/JadRizk/turborepo-launchpad) | 2024-06-10 |
| waitly | A simple and useful waitlist Next.js and Shadcn UI template. | [Link](https://shadcnuikit.com/template/waitly-free-waitlist-template) | 2025-12-19 |
| wordpress-plugin-boilerplate | WordPress Plugin Boilerplate utilizing modern web technologies and tools such as React, TypeScript, SASS, TailwindCSS, Shadcn UI, Vite, Grunt.js, Storybook, HMR, and more. | [Link](https://github.com/prappo/wordpress-plugin-boilerplate) | 2024-09-24 |
## Star History
## Contributors
Thanks goes to all these wonderful people:
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Development & Contributing
### For the Website
- **Development Guide**: See [DEVELOPMENT.md](DEVELOPMENT.md) for setup, architecture, and configuration
- **Contributing**: Fork the repository, create a feature branch, and submit a PR
### For the Awesome List
- **Via Website**: Use the built-in submission form at [awesome-shadcn-ui.vercel.app](https://awesome-shadcn-ui.vercel.app/)
- **Via GitHub**: Follow the [PR template](.github/pull_request_template.md) when creating pull requests
- **Guidelines**: Ensure resources are shadcn/ui related, well-documented, and actively maintained
================================================
FILE: components.json
================================================
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "radix-lyra",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/globals.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"menuColor": "default",
"menuAccent": "subtle",
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {
"@diceui": "https://diceui.com/r/{name}.json"
}
}
================================================
FILE: next.config.mjs
================================================
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
eslint: {
ignoreDuringBuilds: true,
},
typescript: {
ignoreBuildErrors: true,
},
compiler: {
removeConsole:
process.env.NODE_ENV === "production" ? { exclude: ["error"] } : false,
},
};
export default nextConfig;
================================================
FILE: open-next.config.ts
================================================
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
export default defineCloudflareConfig();
================================================
FILE: package.json
================================================
{
"name": "awesome-shadcn-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts",
"format": "prettier --write ./src",
"lint": "next lint",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@base-ui/react": "^1.2.0",
"@hugeicons/core-free-icons": "^3.3.0",
"@hugeicons/react": "^1.1.5",
"@next/third-parties": "^16.1.6",
"@octokit/rest": "^22.0.0",
"@opennextjs/cloudflare": "^1.16.1",
"@radix-ui/react-avatar": "1.1.9",
"@radix-ui/react-dialog": "1.1.13",
"@radix-ui/react-dropdown-menu": "2.1.14",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-navigation-menu": "^1.2.14",
"@radix-ui/react-popover": "1.1.13",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-select": "2.2.4",
"@radix-ui/react-separator": "1.1.6",
"@radix-ui/react-slot": "1.2.2",
"@radix-ui/react-toggle": "1.1.8",
"@radix-ui/react-toggle-group": "1.1.9",
"@radix-ui/react-tooltip": "1.2.6",
"@radix-ui/react-use-controllable-state": "^1.2.2",
"@tailwindcss/postcss": "^4.1.11",
"axios": "^1.12.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.0",
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"eslint-config-next": "^16.0.10",
"input-otp": "^1.4.2",
"lucide-react": "^0.509.0",
"motion": "^12.23.24",
"next": "16.0.10",
"next-themes": "^0.4.6",
"radix-ui": "latest",
"react": "^19.2.3",
"react-day-picker": "^9.14.0",
"react-dom": "^19.2.3",
"react-resizable-panels": "^4.6.5",
"recharts": "2.15.4",
"sonner": "^1.7.4",
"vaul": "^1.1.2"
},
"devDependencies": {
"@types/node": "24.0.10",
"@types/react": "^19",
"prettier": "^3",
"shadcn": "^3.8.5",
"tailwind-merge": "^2.6.0",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.4",
"typescript": "5.8.3",
"wrangler": "^4.61.1"
}
}
================================================
FILE: postcss.config.mjs
================================================
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
================================================
FILE: scripts/add-dates.js
================================================
const fs = require('fs');
const path = 'README.md';
let content;
try {
content = fs.readFileSync(path, 'utf8');
} catch (error) {
console.error(`Error reading README.md: ${error.message}`);
process.exit(1);
}
const lines = content.split('\n');
const currentDate = new Date().toISOString().split('T')[0]; // e.g., 2025-07-02
const updatedLines = [];
let changesCount = 0;
console.log(`Processing README.md with ${lines.length} lines`);
// Function to validate ISO date format (YYYY-MM-DD)
function isValidDate(dateString) {
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (!regex.test(dateString)) return false;
const date = new Date(dateString);
return date instanceof Date && !isNaN(date);
}
let inTable = false;
let tableHasDateColumn = false;
let headerLineCount = 0;
let dateColumnIndex = -1;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Reset table state when hitting a new section
if (line.startsWith('## ')) {
inTable = false;
tableHasDateColumn = false;
headerLineCount = 0;
dateColumnIndex = -1;
}
if (line.startsWith('|')) {
if (!inTable) {
// First line of a new table (header)
inTable = true;
headerLineCount = 1;
// Check if the table header has a date column and find its index
const parts = line.split('|').map(part => part.trim());
dateColumnIndex = parts.findIndex(part => part === 'Date');
tableHasDateColumn = dateColumnIndex > -1;
updatedLines.push(line);
continue;
} else {
headerLineCount++;
}
// Skip header and separator rows
if (headerLineCount <= 2) {
updatedLines.push(line);
continue;
}
// Process data rows
if (tableHasDateColumn && dateColumnIndex > 0) {
// Split the line into parts, preserving the original structure
const parts = line.split('|');
// Ensure we have enough parts for the date column
while (parts.length <= dateColumnIndex + 1) {
parts.push('');
}
// Get the current date value (trimmed)
const currentDateValue = parts[dateColumnIndex].trim();
// Only add date if it's empty, whitespace, or invalid
if (!currentDateValue || currentDateValue === '' || !isValidDate(currentDateValue)) {
parts[dateColumnIndex] = ` ${currentDate} `;
changesCount++;
}
// Reconstruct the line
const newLine = parts.join('|');
updatedLines.push(newLine);
} else {
// No date column or invalid structure, keep as is
updatedLines.push(line);
}
} else {
// Not a table row
updatedLines.push(line);
}
}
// Log summary
console.log(`Completed processing. Made ${changesCount} changes to date columns.`);
if (changesCount > 0) {
try {
fs.writeFileSync(path, updatedLines.join('\n'));
console.log('Changes written to README.md');
} catch (error) {
console.error(`Error writing to README.md: ${error.message}`);
process.exit(1);
}
} else {
console.log('No changes needed, file not modified');
}
================================================
FILE: scripts/format-readme.js
================================================
const fs = require('fs');
const path = 'README.md';
let content;
try {
content = fs.readFileSync(path, 'utf8');
} catch (err) {
console.error(`Error reading README.md: ${err.message}`);
process.exit(1);
}
// Split the content into lines
const lines = content.split('\n');
const updatedLines = [];
let inTable = false;
for (let line of lines) {
if (line.startsWith('|')) {
inTable = true;
// Remove internal line breaks and extra spaces in cells
const parts = line.split('|').map(cell => cell.replace(/\n/g, ' ').trim());
// Rebuild the line with pipes, keeping one line per entry
const formattedLine = '| ' + parts.filter((_, i) => i !== 0 && i !== parts.length - 1 || parts[i] !== '').join(' | ') + ' |';
updatedLines.push(formattedLine);
} else {
if (inTable) {
inTable = false;
}
updatedLines.push(line);
}
}
// Overwrite README.md with the updated lines
try {
fs.writeFileSync(path, updatedLines.join('\n'));
console.log('README.md formatted successfully!');
} catch (err) {
console.error(`Error writing README.md: ${err.message}`);
process.exit(1);
}
================================================
FILE: src/app/[...not-found]/page.tsx
================================================
import { notFound } from "next/navigation";
export default function CatchAllNotFound() {
notFound();
}
================================================
FILE: src/app/api/github/callback/route.ts
================================================
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const code = searchParams.get("code");
const state = searchParams.get("state");
const error = searchParams.get("error");
if (error) {
console.error("GitHub OAuth error:", error);
return NextResponse.redirect(
new URL(`/?error=${encodeURIComponent(error)}`, request.url),
);
}
if (!code) {
console.error("No authorization code received");
return NextResponse.redirect(new URL("/?error=no_code", request.url));
}
// For device flow, we don't need to handle the callback here
// The device flow handles everything through the device-flow endpoint
// This endpoint is just required by GitHub App configuration
console.log("GitHub App callback received:", { code, state });
return NextResponse.redirect(new URL("/?success=authorized", request.url));
}
================================================
FILE: src/app/api/github/device-flow/route.ts
================================================
import { ERROR_MESSAGES, GITHUB_CONFIG } from "@/lib/config";
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
try {
const body = await request.json();
if (body.action === "start") {
// Start the GitHub App device flow
const response = await fetch(GITHUB_CONFIG.DEVICE_FLOW_URL, {
method: "POST",
headers: GITHUB_CONFIG.API_HEADERS,
body: JSON.stringify({
client_id: GITHUB_CONFIG.CLIENT_ID,
scope: GITHUB_CONFIG.SCOPES.join(" "),
}),
});
if (!response.ok) {
const errorText = await response.text();
console.error(
"GitHub device flow start error:",
response.status,
errorText,
);
console.error("Request details:", {
client_id: GITHUB_CONFIG.CLIENT_ID,
scope: GITHUB_CONFIG.SCOPES.join(" "),
url: GITHUB_CONFIG.DEVICE_FLOW_URL,
});
throw new Error(
`${ERROR_MESSAGES.GITHUB_API}: ${response.status} - ${errorText}`,
);
}
const data = await response.json();
return NextResponse.json(data);
} else if (body.action === "poll") {
// Poll for the GitHub App user access token
const response = await fetch(GITHUB_CONFIG.ACCESS_TOKEN_URL, {
method: "POST",
headers: GITHUB_CONFIG.API_HEADERS,
body: JSON.stringify({
client_id: GITHUB_CONFIG.CLIENT_ID,
device_code: body.device_code,
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
}),
});
if (!response.ok) {
const errorText = await response.text();
console.error(
"GitHub device flow poll error:",
response.status,
errorText,
);
throw new Error(
`${ERROR_MESSAGES.GITHUB_API}: ${response.status} - ${errorText}`,
);
}
const data = await response.json();
return NextResponse.json(data);
}
return NextResponse.json(
{ error: ERROR_MESSAGES.INVALID_ACTION },
{ status: 400 },
);
} catch (error: any) {
console.error("GitHub device flow error:", error);
return NextResponse.json(
{ error: error.message || ERROR_MESSAGES.INTERNAL_SERVER },
{ status: 500 },
);
}
}
================================================
FILE: src/app/api/submit-resource/route.ts
================================================
import { NextRequest, NextResponse } from "next/server";
import { Octokit } from "@octokit/rest";
const GITHUB_CONFIG = {
REPO_OWNER: "birobirobiro",
REPO_NAME: "awesome-shadcn-ui",
BRANCH: "main",
};
interface SubmissionData {
name: string;
description: string;
url: string;
category: string;
}
function insertResourceIntoReadme(
readmeContent: string,
submission: SubmissionData,
): { content: string; error?: string } {
const lines = readmeContent.split("\n");
const newEntry = `| ${submission.name} | ${submission.description} | [Link](${submission.url}) |`;
let insertIndex = -1;
let inTargetSection = false;
let inTable = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (
line.startsWith("## ") &&
line.toLowerCase().includes(submission.category.toLowerCase())
) {
inTargetSection = true;
continue;
}
if (
inTargetSection &&
line.startsWith("## ") &&
!line.toLowerCase().includes(submission.category.toLowerCase())
) {
break;
}
if (inTargetSection && line.startsWith("| Name")) {
inTable = true;
continue;
}
if (inTable && line.match(/^\|[\s-]+\|/)) {
continue;
}
if (inTable && line.startsWith("|") && !line.match(/^\|[\s-]+\|/)) {
const parts = line.split("|").map((part) => part.trim());
if (parts.length >= 2) {
const existingName = parts[1];
const existingUrlMatch = line.match(/\[Link\]\(([^)]+)\)/);
const existingUrl = existingUrlMatch ? existingUrlMatch[1] : null;
if (existingName.toLowerCase() === submission.name.toLowerCase()) {
return {
content: "",
error: `Resource "${submission.name}" already exists in this section.`,
};
}
if (
existingUrl &&
existingUrl.toLowerCase() === submission.url.toLowerCase()
) {
return {
content: "",
error: `This URL already exists in this section.`,
};
}
if (existingName.toLowerCase() > submission.name.toLowerCase()) {
insertIndex = i;
break;
}
}
}
if (inTable && (!line.startsWith("|") || line.trim() === "")) {
if (insertIndex === -1) {
insertIndex = i;
}
break;
}
}
if (insertIndex === -1) {
return {
content: "",
error: `Could not find insertion point for category "${submission.category}".`,
};
}
lines.splice(insertIndex, 0, newEntry);
return { content: lines.join("\n") };
}
function generatePRBody(submission: SubmissionData): string {
return `---
name: "feat: Add new awesome resource"
about: "Propose adding a new awesome resource related to shadcn/ui"
labels:
- feature
---
## Describe the awesome resource you want to add
**What is it?**
${submission.description}
## **Which section does it belong to?**
- [x] ${submission.category}
## **Additional details (optional)**
Resource URL: ${submission.url}
## **Checklist**
- [x] Resource is automatically sorted alphabetically within its section.
- [x] Duplicate checking is performed automatically.
- [x] Table formatting is handled automatically.
- [x] Includes a valid and working link to the resource.
- [x] Automatically assigned the correct section to the resource.
`;
}
export async function POST(request: NextRequest) {
try {
const submission: SubmissionData = await request.json();
if (
!submission.name ||
!submission.description ||
!submission.url ||
!submission.category
) {
return NextResponse.json(
{ error: "All fields are required" },
{ status: 400 },
);
}
const githubToken = process.env.GITHUB_TOKEN;
if (!githubToken) {
return NextResponse.json(
{ error: "Server configuration error" },
{ status: 500 },
);
}
const octokit = new Octokit({ auth: githubToken });
const { data: readmeData } = await octokit.repos.getContent({
owner: GITHUB_CONFIG.REPO_OWNER,
repo: GITHUB_CONFIG.REPO_NAME,
path: "README.md",
});
if (
Array.isArray(readmeData) ||
!("content" in readmeData) ||
!readmeData.sha
) {
return NextResponse.json(
{ error: "Could not fetch README" },
{ status: 500 },
);
}
const currentContent = Buffer.from(readmeData.content, "base64").toString();
const insertResult = insertResourceIntoReadme(currentContent, submission);
if (insertResult.error) {
return NextResponse.json({ error: insertResult.error }, { status: 409 });
}
const updatedContent = insertResult.content;
const branchName = `add-${submission.name.toLowerCase().replace(/[^a-z0-9]/g, "-")}-${Date.now()}`;
const { data: ref } = await octokit.git.getRef({
owner: GITHUB_CONFIG.REPO_OWNER,
repo: GITHUB_CONFIG.REPO_NAME,
ref: "heads/main",
});
await octokit.git.createRef({
owner: GITHUB_CONFIG.REPO_OWNER,
repo: GITHUB_CONFIG.REPO_NAME,
ref: `refs/heads/${branchName}`,
sha: ref.object.sha,
});
await octokit.repos.createOrUpdateFileContents({
owner: GITHUB_CONFIG.REPO_OWNER,
repo: GITHUB_CONFIG.REPO_NAME,
path: "README.md",
message: `feat: Add ${submission.name}`,
content: Buffer.from(updatedContent).toString("base64"),
sha: readmeData.sha,
branch: branchName,
});
const prBody = generatePRBody(submission);
const { data: pr } = await octokit.pulls.create({
owner: GITHUB_CONFIG.REPO_OWNER,
repo: GITHUB_CONFIG.REPO_NAME,
title: `feat: Add ${submission.name}`,
head: branchName,
base: "main",
body: prBody,
});
return NextResponse.json({
success: true,
prNumber: pr.number,
prUrl: pr.html_url,
});
} catch (error: any) {
console.error("Error creating PR:", error);
return NextResponse.json(
{ error: error.message || "Failed to create pull request" },
{ status: 500 },
);
}
}
================================================
FILE: src/app/bookmarks/error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertTriangle, ArrowLeft, Home, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useEffect } from "react";
export default function BookmarksError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("Bookmarks error:", error);
}, [error]);
return (
Failed to load bookmarks
We couldn't load this bookmarks page. The bookmarks might not exist
or there's a temporary issue.
{process.env.NODE_ENV === "development" && (
Error Details (Development)
{error.message}
{error.stack && `\n\n${error.stack}`}
)}
);
}
================================================
FILE: src/app/bookmarks/page.tsx
================================================
"use client";
import { ItemGrid } from "@/components/item-grid";
import { PageHeader } from "@/components/layout/page-header";
import { PaginationControls } from "@/components/pagination-controls";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import { useBookmarks } from "@/hooks/use-bookmark";
import { useDebounce } from "@/hooks/use-debounce";
import { fetchAndParseReadme, Resource } from "@/hooks/use-readme";
import { Bookmark, Search } from "lucide-react";
import { motion } from "motion/react";
import Link from "next/link";
import { useCallback, useEffect, useState } from "react";
const ITEMS_PER_PAGE_OPTIONS = [20, 40, 60, 80];
export default function BookmarksPage() {
const [items, setItems] = useState([]);
const [searchQuery, setSearchQuery] = useState("");
const [filteredItems, setFilteredItems] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(ITEMS_PER_PAGE_OPTIONS[0]);
const [isLoading, setIsLoading] = useState(true);
const [showClearDialog, setShowClearDialog] = useState(false);
const {
bookmarkedItems,
toggleBookmark,
clearBookmarks,
isLoading: isBookmarkLoading,
} = useBookmarks();
const debouncedSearchQuery = useDebounce(searchQuery, 300);
useEffect(() => {
async function fetchData() {
try {
setIsLoading(true);
const fetchedResources = await fetchAndParseReadme();
const bookmarkedResources = fetchedResources.filter((item) =>
bookmarkedItems.includes(item.id),
);
setItems(bookmarkedResources);
setFilteredItems(bookmarkedResources);
} catch (error) {
console.error("Error fetching bookmarked items:", error);
} finally {
setIsLoading(false);
}
}
if (!isBookmarkLoading) {
fetchData();
}
}, [bookmarkedItems, isBookmarkLoading]);
useEffect(() => {
if (debouncedSearchQuery) {
const filtered = items.filter(
(item) =>
item.name
?.toLowerCase()
.includes(debouncedSearchQuery.toLowerCase()) ||
item.description
?.toLowerCase()
.includes(debouncedSearchQuery.toLowerCase()),
);
setFilteredItems(filtered);
} else {
setFilteredItems(items);
}
setCurrentPage(1);
}, [debouncedSearchQuery, items]);
const totalPages = Math.ceil(filteredItems.length / itemsPerPage);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = filteredItems.slice(indexOfFirstItem, indexOfLastItem);
const handlePageChange = useCallback((pageNumber: number) => {
setCurrentPage(pageNumber);
}, []);
const handleItemsPerPageChange = useCallback((value: string) => {
setItemsPerPage(Number(value));
setCurrentPage(1);
}, []);
const handleClearBookmarks = useCallback(() => {
clearBookmarks();
setShowClearDialog(false);
setSearchQuery("");
}, [clearBookmarks]);
if (isLoading || isBookmarkLoading) {
return (
{[...Array(6)].map((_, i) => (
))}
);
}
return (
{items.length} {items.length === 1 ? "bookmark" : "bookmarks"}
setSearchQuery(e.target.value)}
className="h-10"
/>
{items.length > 0 && (
)}
}
/>
{items.length === 0 ? (
No bookmarks yet
Start saving your favorite shadcn/ui resources by clicking the
bookmark icon on any item.
) : filteredItems.length === 0 && debouncedSearchQuery ? (
No results found
No bookmarks match your search for "{debouncedSearchQuery}"
) : (
)}
{filteredItems.length > 0 && items.length > 0 && (
)}
{items.length > 0 && (
Showing {indexOfFirstItem + 1} -{" "}
{Math.min(indexOfLastItem, filteredItems.length)} of{" "}
{filteredItems.length}{" "}
{filteredItems.length === 1 ? "bookmark" : "bookmarks"}
)}
);
}
================================================
FILE: src/app/categories/[category]/[id]/error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertTriangle, ArrowLeft, Home, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useEffect } from "react";
export default function ItemError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("Item error:", error);
}, [error]);
return (
Failed to load item
We couldn't load this item page. The item might not exist or there's
a temporary issue.
{process.env.NODE_ENV === "development" && (
Error Details (Development)
{error.message}
{error.stack && `\n\n${error.stack}`}
)}
);
}
================================================
FILE: src/app/categories/[category]/[id]/page.tsx
================================================
"use client";
import { PageHeader } from "@/components/layout/page-header";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { fetchAndParseReadme, Resource } from "@/hooks/use-readme";
import { useWebsitePreview } from "@/hooks/use-website-preview";
import { categoryNameToSlug, slugToCategoryName } from "@/lib/slugs";
import { format, isValid, parseISO } from "date-fns";
import {
Calendar,
ExternalLink,
Github,
Globe,
Tag,
Image,
} from "lucide-react";
import { motion } from "motion/react";
import Link from "next/link";
import { use, useEffect, useState } from "react";
interface ItemPageProps {
params: Promise<{
category: string;
id: string;
}>;
}
const CATEGORY_DESCRIPTIONS: Record = {
"Libs and Components":
"Essential libraries and reusable components built with shadcn/ui",
Registries: "Component registries and collections for shadcn/ui",
"Plugins and Extensions":
"Tools and extensions that enhance your shadcn/ui workflow",
"Colors and Customizations":
"Themes, color palettes, and customization utilities",
Animations: "Animation libraries and motion components for shadcn/ui",
Tools: "Development tools, generators, and utilities for shadcn/ui projects",
"Websites and Portfolios Inspirations":
"Real-world examples and inspiration for your projects",
Platforms: "Platforms and services that integrate with shadcn/ui",
Ports: "Ports of shadcn/ui to other frameworks and technologies",
"Design System": "Complete design systems and component libraries",
"Boilerplates / Templates":
"Starter templates and boilerplates for quick project setup",
};
export default function ItemPage({ params }: ItemPageProps) {
const resolvedParams = use(params);
const [item, setItem] = useState(null);
const [relatedItems, setRelatedItems] = useState([]);
const [faviconUrl, setFaviconUrl] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const categorySlug = resolvedParams.category;
const categoryName = slugToCategoryName(categorySlug);
const itemId = resolvedParams.id;
useEffect(() => {
async function fetchData() {
try {
setIsLoading(true);
const fetchedResources = await fetchAndParseReadme();
const foundItem = fetchedResources.find(
(resource) => resource.id === itemId,
);
if (foundItem) {
setItem(foundItem);
const related = fetchedResources
.filter(
(resource) =>
resource.category === foundItem.category &&
resource.id !== foundItem.id,
)
.slice(0, 6);
setRelatedItems(related);
const domain = new URL(foundItem.url).hostname;
setFaviconUrl(`https://icons.duckduckgo.com/ip3/${domain}.ico`);
}
} catch (error) {
console.error("Error fetching item data:", error);
} finally {
setIsLoading(false);
}
}
fetchData();
}, [itemId, categoryName]);
const formatDate = (dateString: string) => {
if (dateString === "Unknown") return "Unknown";
const date = parseISO(dateString);
return isValid(date) ? format(date, "MMMM d, yyyy") : "Unknown";
};
const isGitHubUrl = (url: string) => {
return url.includes("github.com");
};
if (isLoading) {
return (
{[...Array(6)].map((_, i) => (
))}
);
}
if (!item) {
return null;
}
// Component to render preview based on state
const WebsitePreview = () => {
const { previewState, screenshotUrl } = useWebsitePreview({
url: item.url,
name: item.name,
});
if (previewState === "loading") {
return (
);
}
if (previewState === "iframe") {
return (
<>
Visit {item.name} website
Visit website
Click to open
>
);
}
if (previewState === "screenshot" && screenshotUrl) {
return (
<>
Visit website
Screenshot preview
Visit {item.name} website
>
);
}
// Fallback state
return (
Preview not available
This website blocks embedding. Click below to visit directly.
);
};
return (
setFaviconUrl(null)}
/>
) : (
)
}
breadcrumbs={[
{ label: "Categories", href: "/categories" },
{ label: categoryName, href: `/categories/${categorySlug}` },
{
label: item.name || "Loading...",
href: `/categories/${categorySlug}/${itemId}`,
},
]}
actions={
Added {formatDate(item.date)}
•
{item.category}
}
/>
Preview
Category
{item.category}
{CATEGORY_DESCRIPTIONS[item.category] ||
"A collection of shadcn/ui related resources"}
{relatedItems.length > 0 && (
Related Items
{relatedItems.map((relatedItem) => (
{relatedItem.name}
{relatedItem.description}
View
))}
)}
);
}
================================================
FILE: src/app/categories/[category]/error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertTriangle, ArrowLeft, Home, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useEffect } from "react";
export default function CategoryError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("Category error:", error);
}, [error]);
return (
Failed to load category
We couldn't load this category page. The category might not exist or
there's a temporary issue.
{process.env.NODE_ENV === "development" && (
Error Details (Development)
{error.message}
{error.stack && `\n\n${error.stack}`}
)}
);
}
================================================
FILE: src/app/categories/[category]/page.tsx
================================================
"use client";
import { ItemGrid } from "@/components/item-grid";
import { PageHeader } from "@/components/layout/page-header";
import { PaginationControls } from "@/components/pagination-controls";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import { useBookmarks } from "@/hooks/use-bookmark";
import { useDebounce } from "@/hooks/use-debounce";
import { fetchAndParseReadme, Resource } from "@/hooks/use-readme";
import { slugToCategoryName } from "@/lib/slugs";
import { motion } from "motion/react";
import { use, useCallback, useEffect, useState } from "react";
interface CategoryPageProps {
params: Promise<{
category: string;
}>;
}
const CATEGORY_DESCRIPTIONS: Record = {
"Libs and Components":
"Essential libraries and reusable components built with shadcn/ui",
Registries: "Component registries and collections for shadcn/ui",
"Plugins and Extensions":
"Tools and extensions that enhance your shadcn/ui workflow",
"Colors and Customizations":
"Themes, color palettes, and customization utilities",
Animations: "Animation libraries and motion components for shadcn/ui",
Tools: "Development tools, generators, and utilities for shadcn/ui projects",
"Websites and Portfolios Inspirations":
"Real-world examples and inspiration for your projects",
Platforms: "Platforms and services that integrate with shadcn/ui",
Ports: "Ports of shadcn/ui to other frameworks and technologies",
"Design System": "Complete design systems and component libraries",
"Boilerplates / Templates":
"Starter templates and boilerplates for quick project setup",
};
const ITEMS_PER_PAGE_OPTIONS = [20, 40, 60, 80];
export default function CategoryPage({ params }: CategoryPageProps) {
const resolvedParams = use(params);
const [items, setItems] = useState([]);
const [searchQuery, setSearchQuery] = useState("");
const [filteredItems, setFilteredItems] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(ITEMS_PER_PAGE_OPTIONS[1]);
const [isLoading, setIsLoading] = useState(true);
const {
bookmarkedItems,
toggleBookmark,
isLoading: isBookmarkLoading,
} = useBookmarks();
const debouncedSearchQuery = useDebounce(searchQuery, 300);
const categorySlug = resolvedParams.category;
const categoryName = slugToCategoryName(categorySlug);
useEffect(() => {
async function fetchData() {
try {
setIsLoading(true);
const fetchedResources = await fetchAndParseReadme();
const categoryItems = fetchedResources.filter(
(item) => item.category === categoryName,
);
setItems(categoryItems);
setFilteredItems(categoryItems);
} catch (error) {
console.error("Error fetching category items:", error);
} finally {
setIsLoading(false);
}
}
fetchData();
}, [categoryName]);
useEffect(() => {
if (debouncedSearchQuery) {
const filtered = items.filter(
(item) =>
item.name
?.toLowerCase()
.includes(debouncedSearchQuery.toLowerCase()) ||
item.description
?.toLowerCase()
.includes(debouncedSearchQuery.toLowerCase()),
);
setFilteredItems(filtered);
} else {
setFilteredItems(items);
}
setCurrentPage(1);
}, [debouncedSearchQuery, items]);
const totalPages = Math.ceil(filteredItems.length / itemsPerPage);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = filteredItems.slice(indexOfFirstItem, indexOfLastItem);
const handlePageChange = useCallback((pageNumber: number) => {
setCurrentPage(pageNumber);
}, []);
const handleItemsPerPageChange = useCallback((value: string) => {
setItemsPerPage(Number(value));
setCurrentPage(1);
}, []);
if (isLoading) {
return (
{[...Array(6)].map((_, i) => (
))}
);
}
return (
{items.length} {items.length === 1 ? "item" : "items"}
•
Category
setSearchQuery(e.target.value)}
className="h-10"
/>
}
/>
{filteredItems.length > 0 && (
)}
Showing {indexOfFirstItem + 1} -{" "}
{Math.min(indexOfLastItem, filteredItems.length)} of{" "}
{filteredItems.length} items
{filteredItems.length === 0 && debouncedSearchQuery && (
No items found for "{debouncedSearchQuery}"
)}
);
}
================================================
FILE: src/app/categories/error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertTriangle, Home, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useEffect } from "react";
export default function CategoriesError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("Categories error:", error);
}, [error]);
return (
Failed to load categories
We couldn't load the categories page. This might be a temporary
issue with our data source.
{process.env.NODE_ENV === "development" && (
Error Details (Development)
{error.message}
{error.stack && `\n\n${error.stack}`}
)}
);
}
================================================
FILE: src/app/categories/page.tsx
================================================
"use client";
import { PageHeader } from "@/components/layout/page-header";
import { Badge } from "@/components/ui/badge";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { fetchAndParseReadme, Resource } from "@/hooks/use-readme";
import { categoryNameToSlug } from "@/lib/slugs";
import { ArrowRight } from "lucide-react";
import { motion } from "motion/react";
import Link from "next/link";
import { useEffect, useState } from "react";
interface Category {
title: string;
items: Resource[];
description: string;
}
const CATEGORY_DESCRIPTIONS: Record = {
"Libs and Components":
"Essential libraries and reusable components built with shadcn/ui",
Registries: "Component registries and collections for shadcn/ui",
"Plugins and Extensions":
"Tools and extensions that enhance your shadcn/ui workflow",
"Colors and Customizations":
"Themes, color palettes, and customization utilities",
Animations: "Animation libraries and motion components for shadcn/ui",
Tools: "Development tools, generators, and utilities for shadcn/ui projects",
"Websites and Portfolios Inspirations":
"Real-world examples and inspiration for your projects",
Platforms: "Platforms and services that integrate with shadcn/ui",
Ports: "Ports of shadcn/ui to other frameworks and technologies",
"Design System": "Complete design systems and component libraries",
"Boilerplates / Templates":
"Starter templates and boilerplates for quick project setup",
};
export default function CategoriesPage() {
const [categories, setCategories] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
async function fetchData() {
try {
setIsLoading(true);
const fetchedResources = await fetchAndParseReadme();
const EXCLUDED_CATEGORIES = ["Star History", "Contributors"];
const groupedCategories = fetchedResources.reduce(
(acc, resource) => {
if (!EXCLUDED_CATEGORIES.includes(resource.category)) {
if (!acc[resource.category]) {
acc[resource.category] = [];
}
acc[resource.category].push(resource);
}
return acc;
},
{} as Record,
);
const formattedCategories = Object.entries(groupedCategories).map(
([title, items]) => ({
title,
items,
description:
CATEGORY_DESCRIPTIONS[title] ||
"A collection of shadcn/ui related resources",
}),
);
setCategories(formattedCategories);
} catch (error) {
console.error("Error fetching categories:", error);
} finally {
setIsLoading(false);
}
}
fetchData();
}, []);
if (isLoading) {
return (
{[...Array(9)].map((_, i) => (
))}
);
}
return (
{categories.map((category) => (
{category.title}
{category.description}
{category.items.length}{" "}
{category.items.length === 1 ? "item" : "items"}
))}
);
}
================================================
FILE: src/app/error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertTriangle, RefreshCw } from "lucide-react";
import { useEffect } from "react";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error("Homepage error:", error);
}, [error]);
return (
Something went wrong
We encountered an error while loading the homepage. This might be a
temporary issue.
{process.env.NODE_ENV === "development" && (
Error Details (Development)
{error.message}
{error.stack && `\n\n${error.stack}`}
)}
);
}
================================================
FILE: src/app/global-error.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import { AlertOctagon } from "lucide-react";
import { useEffect } from "react";
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log error
}, [error]);
return (
Critical Error
We've encountered a critical application error.
Our team has been automatically notified and is working to resolve
the issue.
{error.digest && (
Error ID: {error.digest}
)}
);
}
================================================
FILE: src/app/globals.css
================================================
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
:root {
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.21 0.006 285.885);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.705 0.015 286.067);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.141 0.005 285.823);
--sidebar-primary: oklch(0.21 0.006 285.885);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.967 0.001 286.375);
--sidebar-accent-foreground: oklch(0.21 0.006 285.885);
--sidebar-border: oklch(0.92 0.004 286.32);
--sidebar-ring: oklch(0.705 0.015 286.067);
/* Custom colors for donation button */
--donation-bg: oklch(0.95 0.15 95);
--donation-bg-hover: oklch(0.92 0.18 95);
--donation-text: oklch(0.15 0 0);
--font-sans: Geist, sans-serif;
--font-serif: Georgia, serif;
--font-mono: Geist Mono, monospace;
--radius: 0.625rem;
--shadow-x: 0px;
--shadow-y: 1px;
--shadow-blur: 2px;
--shadow-spread: 0px;
--shadow-opacity: 0.18;
--shadow-color: hsl(0 0% 0%);
--shadow-2xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.09);
--shadow-xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.09);
--shadow-sm:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 1px 2px -1px hsl(0 0% 0% / 0.18);
--shadow:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 1px 2px -1px hsl(0 0% 0% / 0.18);
--shadow-md:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 2px 4px -1px hsl(0 0% 0% / 0.18);
--shadow-lg:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 4px 6px -1px hsl(0 0% 0% / 0.18);
--shadow-xl:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 8px 10px -1px hsl(0 0% 0% / 0.18);
--shadow-2xl: 0px 1px 2px 0px hsl(0 0% 0% / 0.45);
--tracking-normal: 0em;
--spacing: 0.25rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.92 0.004 286.32);
--primary-foreground: oklch(0.21 0.006 285.885);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--destructive-foreground: oklch(0 0 0);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.552 0.016 285.938);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.552 0.016 285.938);
/* Custom colors for donation button */
--donation-bg: oklch(0.95 0.15 95);
--donation-bg-hover: oklch(0.92 0.18 95);
--donation-text: oklch(0.15 0 0);
--font-sans: Geist, sans-serif;
--font-serif: Georgia, serif;
--font-mono: Geist Mono, monospace;
--radius: 0.5rem;
--shadow-x: 0px;
--shadow-y: 1px;
--shadow-blur: 2px;
--shadow-spread: 0px;
--shadow-opacity: 0.18;
--shadow-color: hsl(0 0% 0%);
--shadow-2xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.09);
--shadow-xs: 0px 1px 2px 0px hsl(0 0% 0% / 0.09);
--shadow-sm:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 1px 2px -1px hsl(0 0% 0% / 0.18);
--shadow:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 1px 2px -1px hsl(0 0% 0% / 0.18);
--shadow-md:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 2px 4px -1px hsl(0 0% 0% / 0.18);
--shadow-lg:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 4px 6px -1px hsl(0 0% 0% / 0.18);
--shadow-xl:
0px 1px 2px 0px hsl(0 0% 0% / 0.18), 0px 8px 10px -1px hsl(0 0% 0% / 0.18);
--shadow-2xl: 0px 1px 2px 0px hsl(0 0% 0% / 0.45);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--color-donation-bg: var(--donation-bg);
--color-donation-bg-hover: var(--donation-bg-hover);
--color-donation-text: var(--donation-text);
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--font-serif: var(--font-serif);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--shadow-2xs: var(--shadow-2xs);
--shadow-xs: var(--shadow-xs);
--shadow-sm: var(--shadow-sm);
--shadow: var(--shadow);
--shadow-md: var(--shadow-md);
--shadow-lg: var(--shadow-lg);
--shadow-xl: var(--shadow-xl);
--shadow-2xl: var(--shadow-2xl);
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
--tracking-normal: var(--tracking-normal);
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
--radius-4xl: calc(var(--radius) + 16px);
--animate-marquee-left: marquee-left var(--marquee-duration) linear var(--marquee-loop-count);
--animate-marquee-right: marquee-right var(--marquee-duration) linear var(--marquee-loop-count);
--animate-marquee-left-rtl: marquee-left-rtl var(--marquee-duration) linear var(--marquee-loop-count);
--animate-marquee-right-rtl: marquee-right-rtl var(--marquee-duration) linear var(--marquee-loop-count);
--animate-marquee-up: marquee-up var(--marquee-duration) linear var(--marquee-loop-count);
--animate-marquee-down: marquee-down var(--marquee-duration) linear var(--marquee-loop-count);
@keyframes marquee-left {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(calc(-100% - var(--marquee-gap)));
}
}
@keyframes marquee-right {
0% {
transform: translateX(calc(-100% - var(--marquee-gap)));
}
100% {
transform: translateX(0%);
}
}
@keyframes marquee-up {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(calc(-100% - var(--marquee-gap)));
}
}
@keyframes marquee-down {
0% {
transform: translateY(calc(-100% - var(--marquee-gap)));
}
100% {
transform: translateY(0%);
}
}
@keyframes marquee-left-rtl {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(calc(100% + var(--marquee-gap)));
}
}
@keyframes marquee-right-rtl {
0% {
transform: translateX(calc(100% + var(--marquee-gap)));
}
100% {
transform: translateX(0%);
}
}
}
body {
letter-spacing: var(--tracking-normal);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
html {
scroll-behavior: smooth;
}
body {
@apply bg-background text-foreground;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.font-mono {
font-family: var(--font-mono);
}
.text-terminal {
font-family: var(--font-mono);
letter-spacing: -0.02em;
}
}
================================================
FILE: src/app/layout.tsx
================================================
import { Footer } from "@/components/layout/footer";
import { Header } from "@/components/layout/header";
import { Providers } from "@/providers/providers";
import { type Metadata, type Viewport } from "next";
import { GoogleAnalytics } from "@next/third-parties/google";
import Script from "next/script";
import { TooltipProvider } from "@/components/ui/tooltip";
import type React from "react";
import { Suspense } from "react";
import { cn } from "@/lib/utils";
import "@/app/globals.css";
import { Geist, Geist_Mono } from "next/font/google";
export const metadata: Metadata = {
metadataBase: new URL("https://awesome-shadcn-ui.vercel.app"),
title: {
default: "awesome-shadcn-ui",
template: `%s | awesome-shadcn-ui`,
},
description: "A curated list of awesome things related to shadcn/ui",
keywords: [
"shadcn",
"ui library",
"awesome",
"github",
"readme",
"shad",
"awesome list",
"awesome shad",
"shadcn ui",
],
alternates: {
canonical: "https://awesome-shadcn-ui.vercel.app/",
},
openGraph: {
type: "website",
locale: "en_US",
url: "https://awesome-shadcn-ui.vercel.app/",
siteName: "awesome-shadcn-ui",
title: "awesome-shadcn-ui",
description: "A curated list of awesome things related to shadcn/ui",
images: [
{
url: "/seo.png",
width: 1200,
height: 630,
alt: "awesome-shadcn-ui",
},
],
},
twitter: {
creator: "@birobirobiro",
site: "@birobirobiro",
card: "summary_large_image",
title: "awesome-shadcn-ui",
description: "A curated list of awesome things related to shadcn/ui",
images: ["/seo.png"],
},
icons: {
icon: "/favicon.ico",
},
};
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
maximumScale: 1,
userScalable: false,
};
const geistSans = Geist({
variable: "--font-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-mono",
subsets: ["latin"],
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
{process.env.HIMETRICA_API_KEY && (
)}
{children}
);
}
================================================
FILE: src/app/not-found.tsx
================================================
import { Button } from "@/components/ui/button";
import Link from "next/link";
export default function NotFound() {
return (
Page Not Found
Sorry, we couldn't find the page you're looking for.
It might have been moved, deleted, or the URL might be incorrect.
);
}
================================================
FILE: src/app/page.tsx
================================================
"use client";
import { SubmitCTA } from "@/components/sections/cta-submit";
import Hero from "@/components/sections/hero";
import ItemList from "@/components/sections/items-list";
import { Resource, fetchAndParseReadme } from "@/hooks/use-readme";
import { isValid, parseISO } from "date-fns";
import { motion } from "motion/react";
import { useEffect, useState } from "react";
interface Category {
title: string;
items: Resource[];
}
const EXCLUDED_CATEGORIES = ["Star History", "Contributors"];
export default function Home() {
const [categories, setCategories] = useState([]);
const [filteredItems, setFilteredItems] = useState([]);
useEffect(() => {
async function fetchData() {
const fetchedResources = await fetchAndParseReadme();
const groupedCategories = fetchedResources.reduce(
(acc, resource) => {
if (!EXCLUDED_CATEGORIES.includes(resource.category)) {
if (!acc[resource.category]) {
acc[resource.category] = [];
}
acc[resource.category].push(resource);
}
return acc;
},
{} as Record,
);
const formattedCategories = Object.entries(groupedCategories).map(
([title, items]) => ({
title,
items,
}),
);
const eligibleItems = fetchedResources.filter(
(item) => !EXCLUDED_CATEGORIES.includes(item.category),
);
const sortedItems = eligibleItems.sort((a, b) => {
const dateA =
a.date && a.date !== "Unknown" ? parseISO(a.date) : new Date(0);
const dateB =
b.date && b.date !== "Unknown" ? parseISO(b.date) : new Date(0);
if (!isValid(dateA)) return 1;
if (!isValid(dateB)) return -1;
return dateB.getTime() - dateA.getTime();
});
setCategories(formattedCategories);
setFilteredItems(sortedItems);
}
fetchData();
}, []);
return (
);
}
================================================
FILE: src/components/github-stars.tsx
================================================
"use client";
import { Octokit } from "@octokit/rest";
import { useEffect, useState } from "react";
async function getStars() {
const octokit = new Octokit();
const { data } = await octokit.repos.get({
owner: "birobirobiro",
repo: "awesome-shadcn-ui",
});
return data.stargazers_count;
}
export function GithubStars() {
const [stars, setStars] = useState(null);
useEffect(() => {
getStars().then(setStars);
}, []);
if (stars === null) return null;
const formattedStars =
stars >= 1000 ? `${(stars / 1000).toFixed(1)}k` : stars;
return {formattedStars};
}
================================================
FILE: src/components/item-card.tsx
================================================
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { ArrowRight, Bookmark, ExternalLink } from "lucide-react";
import { Button } from "@/components/ui/button";
import { categoryNameToSlug } from "@/lib/slugs";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import React from "react";
interface ItemCardProps {
id: string;
title: string;
description: string;
url: string;
category: string;
date?: string;
isBookmarked: boolean;
onBookmark: (id: string) => void;
isBookmarkLoading?: boolean;
}
const standardAnimations = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
transition: { duration: 0.2, ease: "easeOut" },
};
const ItemCard: React.FC = ({
id,
title,
description,
url,
category,
date,
isBookmarked,
onBookmark,
isBookmarkLoading = false,
}) => {
const handleCardClick = () => {
window.location.href = `/categories/${categoryNameToSlug(category)}/${id}`;
};
return (
{title}
{description}
{date && (
Added: {date}
)}
{/* Bookmark Button */}
{/* External Link Button */}
);
};
export default ItemCard;
================================================
FILE: src/components/item-grid.tsx
================================================
import React from "react";
import { Resource } from "@/hooks/use-readme";
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
import ItemCard from "./item-card";
import SponsorCard from "./sponsor-card";
import { sponsors } from "@/components/sponsors/sponsors";
const SPONSOR_INTERVAL = 8;
interface ItemGridProps {
items: Resource[];
bookmarkedItems: string[];
onBookmark: (id: string) => void;
isBookmarkLoading?: boolean;
}
export function ItemGrid({
items,
bookmarkedItems,
onBookmark,
isBookmarkLoading = false,
}: ItemGridProps) {
if (items.length === 0) {
return (
No items found matching your criteria.
Try adjusting your search or filter settings.
);
}
const gridItems: React.ReactNode[] = [];
items.forEach((item, index) => {
gridItems.push(
);
if (index % SPONSOR_INTERVAL === 0 && sponsors.length > 0) {
const sponsor = sponsors[Math.floor(index / SPONSOR_INTERVAL) % sponsors.length];
gridItems.push(
);
}
});
return (
{gridItems}
);
}
================================================
FILE: src/components/kibo-ui/theme-switcher/index.tsx
================================================
"use client";
import { useTheme } from "next-themes";
import { Monitor, Moon, Sun } from "lucide-react";
import { motion } from "motion/react";
import { useCallback, useEffect, useState } from "react";
import { cn } from "@/lib/utils";
const themes = [
{
key: "system",
icon: Monitor,
label: "System theme",
},
{
key: "light",
icon: Sun,
label: "Light theme",
},
{
key: "dark",
icon: Moon,
label: "Dark theme",
},
];
export type ThemeSwitcherProps = {
value?: "light" | "dark" | "system";
onChange?: (theme: "light" | "dark" | "system") => void;
defaultValue?: "light" | "dark" | "system";
className?: string;
};
export const ThemeSwitcher = ({
value,
onChange,
defaultValue = "system",
className,
}: ThemeSwitcherProps) => {
const { theme, setTheme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
const handleThemeClick = useCallback(
(themeKey: "light" | "dark" | "system") => {
setTheme(themeKey);
onChange?.(themeKey);
},
[setTheme, onChange],
);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
const currentTheme = value || theme || defaultValue;
return (
{themes.map(({ key, icon: Icon, label }) => {
const isActive = currentTheme === key;
return (
);
})}
);
};
================================================
FILE: src/components/layout/footer.tsx
================================================
"use client";
import { Separator } from "@/components/ui/separator";
import { ThemeSwitcher } from "@/components/kibo-ui/theme-switcher";
import { useCategories } from "@/hooks/use-categories";
import { ArrowRight, ExternalLink, Github } from "lucide-react";
import { motion, useInView } from "motion/react";
import Link from "next/link";
import { useRef } from "react";
import { Button } from "../ui/button";
import { GithubStars } from "@/components/github-stars";
export function Footer() {
const { categories } = useCategories();
const ref = useRef(null);
const isInView = useInView(ref, { once: true, amount: 0.3 });
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
delayChildren: 0.2,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
const quickLinks = [
{ name: "Home", href: "/" },
{ name: "Categories", href: "/categories" },
{
name: "GitHub",
href: "https://github.com/birobirobiro/awesome-shadcn-ui",
external: true,
},
];
const socialLinks = [
{
name: "GitHub",
href: "https://github.com/birobirobiro/awesome-shadcn-ui",
icon: Github,
},
];
return (
);
}
================================================
FILE: src/components/layout/header.tsx
================================================
"use client";
import { PRSubmissionDialog } from "@/components/pr-submission-dialog";
import { ThemeSwitcher } from "@/components/kibo-ui/theme-switcher";
import { Button } from "@/components/ui/button";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Github, Menu } from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";
import { sponsors } from "@/components/sponsors/sponsors";
import { GithubStars } from "@/components/github-stars";
import { Logo } from "@/components/logo";
import { ModeToggle } from "@/components/theme-toggle";
export function Header() {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const pathname = usePathname();
return (
{/* Left: Logo + Navigation */}
{/* Navigation - Desktop */}
{/* Right: Actions */}
{/* Sponsorship - Desktop */}
{sponsors.map((sponsor) => (
{sponsor.LogoComponent}
{sponsor.name}
{sponsor.description}
))}
{/* Submit Button - Desktop - REMOVED, now in search filters */}
{/* Mobile Menu */}
{/* Header */}
setMobileMenuOpen(false)}
className="flex items-center gap-3"
>
{/* Navigation */}
{/* Sponsored Section */}
);
}
================================================
FILE: src/components/layout/page-header.tsx
================================================
"use client";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { motion } from "motion/react";
import Link from "next/link";
import React, { ReactNode } from "react";
interface PageHeaderProps {
title: string;
description: string;
icon?: ReactNode;
breadcrumbs?: Array<{
label: string;
href: string;
}>;
actions?: ReactNode;
className?: string;
}
export function PageHeader({
title,
description,
icon,
breadcrumbs = [],
actions,
className = "",
}: PageHeaderProps) {
return (
{breadcrumbs.length > 0 && (
Home
{breadcrumbs.map((breadcrumb, index) => (
{index === breadcrumbs.length - 1 ? (
{breadcrumb.label}
) : (
{breadcrumb.label}
)}
))}
)}
{icon}
{title}
{description}
{actions &&
{actions}
}
);
}
================================================
FILE: src/components/logo.tsx
================================================
import Image from "next/image";
interface LogoProps {
className?: string;
}
export function Logo({ className = "h-5 w-auto" }: LogoProps) {
return (
);
}
export function HeroLogo({ className = "h-40 w-auto" }: LogoProps) {
return (
);
}
================================================
FILE: src/components/pagination-controls.tsx
================================================
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { motion } from "motion/react";
interface PaginationControlsProps {
currentPage: number;
totalPages: number;
itemsPerPage: number;
handlePageChange: (pageNumber: number) => void;
handleItemsPerPageChange: (value: string) => void;
itemsPerPageOptions: number[];
}
export function PaginationControls({
currentPage,
totalPages,
itemsPerPage,
handlePageChange,
handleItemsPerPageChange,
itemsPerPageOptions,
}: PaginationControlsProps) {
return (
Items per page:
Page {currentPage} of {totalPages}
);
}
================================================
FILE: src/components/pr-submission-dialog.tsx
================================================
"use client";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { SubmissionData, usePRSubmission } from "@/hooks/use-pr-submission";
import {
AlertCircle,
ArrowRight,
CheckCircle2,
Loader2,
Plus,
} from "lucide-react";
import { useCallback, useState } from "react";
import { toast } from "sonner";
const CATEGORIES = [
"Libs and Components",
"Registries",
"Plugins and Extensions",
"Colors and Customizations",
"Animations",
"Tools",
"Websites and Portfolios Inspirations",
"Platforms",
"Ports",
"Design System",
"Boilerplates / Templates",
];
interface PRSubmissionDialogProps {
trigger?: React.ReactNode;
}
export function PRSubmissionDialog({ trigger }: PRSubmissionDialogProps) {
const [open, setOpen] = useState(false);
const [step, setStep] = useState<"form" | "success">("form");
const [formData, setFormData] = useState({
name: "",
description: "",
url: "",
category: "",
});
const [submissionResult, setSubmissionResult] = useState<{
prNumber?: number;
prUrl?: string;
} | null>(null);
const {
isSubmitting,
error: submissionError,
submissionStatus,
submitPR,
} = usePRSubmission();
const handleSubmit = useCallback(async () => {
if (
!formData.name ||
!formData.description ||
!formData.url ||
!formData.category
) {
toast.error("Please fill in all fields");
return;
}
const result = await submitPR(null, formData, { login: "" });
if (result.success) {
setSubmissionResult({
prNumber: result.prNumber,
prUrl: result.prUrl,
});
setStep("success");
toast.success("Pull request submitted successfully!");
} else {
toast.error(result.error || "Failed to submit pull request");
}
}, [formData, submitPR]);
const handleClose = useCallback(() => {
setOpen(false);
setTimeout(() => {
setStep("form");
setFormData({ name: "", description: "", url: "", category: "" });
setSubmissionResult(null);
}, 300);
}, []);
const handleOpenChange = useCallback(
(isOpen: boolean) => {
if (!isOpen) {
handleClose();
} else {
setOpen(true);
}
},
[handleClose],
);
const renderFormStep = () => (
Submit a New Resource
Add a new entry to the awesome shadcn/ui list
);
const renderSuccessStep = () => (
PR Created Successfully!
Your pull request has been created automatically
{submissionResult && (
PR #{submissionResult.prNumber}
PR will be reviewed by maintainers
)}
);
return (
);
}
================================================
FILE: src/components/search-filter-controls.tsx
================================================
import Sort, { SortOption } from "@/components/sort";
import { Input } from "@/components/ui/input";
import { MultiSelect } from "@/components/ui/multi-select";
import { Button } from "@/components/ui/button";
import { PRSubmissionDialog } from "@/components/pr-submission-dialog";
import { motion } from "motion/react";
import type React from "react";
import { useCallback } from "react";
import { Github } from "lucide-react";
interface SearchFilterControlsProps {
searchQuery: string;
setSearchQuery: (query: string) => void;
categoryOptions: { label: string; value: string }[];
selectedCategories: string[];
setSelectedCategories: (categories: string[]) => void;
sortOption: SortOption;
onSortChange: (option: SortOption) => void;
}
export function SearchFilterControls({
searchQuery,
setSearchQuery,
categoryOptions,
selectedCategories,
setSelectedCategories,
sortOption,
onSortChange,
}: SearchFilterControlsProps) {
const handleSearchChange = useCallback(
(e: React.ChangeEvent) => {
setSearchQuery(e.target.value);
},
[setSearchQuery],
);
return (
Submit new resource
}
/>
);
}
================================================
FILE: src/components/sections/cta-submit.tsx
================================================
"use client";
import { Card, CardContent } from "@/components/ui/card";
import { motion, useInView } from "motion/react";
import { ArrowRight, Github } from "lucide-react";
import { PRSubmissionDialog } from "@/components/pr-submission-dialog";
import { Button } from "@/components/ui/button";
import { useRef } from "react";
export function SubmitCTA() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, amount: 0.5 });
const containerVariants = {
hidden: { opacity: 0, y: 10 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.3,
staggerChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 10 },
visible: { opacity: 1, y: 0 },
};
return (
Contribute to awesome-shadcn/ui
Have an awesome shadcn/ui related project or resource? Share it
with the community! Open a PR and help grow this curated list.
);
}
================================================
FILE: src/components/sections/hero.tsx
================================================
"use client";
import { HeroLogo } from "@/components/logo";
import { Sponsorship } from "./sponsorship";
import { motion } from "motion/react";
const fadeIn = {
hidden: { opacity: 0, y: 8 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.4,
ease: [0.22, 1, 0.36, 1],
},
},
};
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.06,
delayChildren: 0.1,
},
},
};
export default function Hero() {
return (
{/* Logo */}
{/* Title */}
awesome-shadcn/ui
{/* Description */}
A curated list of awesome things related to{" "}
shadcn/ui
{/* Credits */}
Created by{" "}
birobirobiro.dev
·
Site by{" "}
bankkroll.xyz
{/* Sponsorship */}
);
}
================================================
FILE: src/components/sections/items-list.tsx
================================================
"use client";
import { isValid, parseISO } from "date-fns";
import { AnimatePresence, motion } from "motion/react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Card, CardContent, CardFooter, CardHeader } from "../ui/card";
import { SortOption } from "@/components/sort";
import { useBookmarks } from "@/hooks/use-bookmark";
import { useDebounce } from "@/hooks/use-debounce";
import { Resource } from "@/hooks/use-readme";
import { ItemGrid } from "../item-grid";
import { PaginationControls } from "../pagination-controls";
import { SearchFilterControls } from "../search-filter-controls";
import { Skeleton } from "../ui/skeleton";
const ITEMS_PER_PAGE_OPTIONS = [20, 40, 60, 80];
interface Category {
title: string;
items: Resource[];
}
interface ItemListProps {
items: Resource[];
categories: Category[];
}
export default function ItemList({
items: initialItems,
categories,
}: ItemListProps) {
const [filteredItems, setFilteredItems] = useState(initialItems);
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(ITEMS_PER_PAGE_OPTIONS[1]);
const [searchQuery, setSearchQuery] = useState("");
const [selectedCategories, setSelectedCategories] = useState([]);
const [sortOption, setSortOption] = useState("date-desc");
const [isLoading, setIsLoading] = useState(true);
const debouncedSearchQuery = useDebounce(searchQuery, 300);
const {
bookmarkedItems,
toggleBookmark,
isLoading: isBookmarkLoading,
} = useBookmarks();
const categoryOptions = useMemo(
() =>
categories.map((category) => ({
label: category.title,
value: category.title,
})),
[categories],
);
const sortItems = useCallback(
(items: Resource[]): Resource[] => {
return [...items].sort((a, b) => {
const aBookmarked = bookmarkedItems.includes(a.id);
const bBookmarked = bookmarkedItems.includes(b.id);
if (aBookmarked !== bBookmarked) return aBookmarked ? -1 : 1;
const [field, direction] = sortOption.split("-") as [
"date" | "name",
"asc" | "desc",
];
if (field === "name") {
const nameA = a.name?.toLowerCase() || "";
const nameB = b.name?.toLowerCase() || "";
const result = nameA.localeCompare(nameB);
return direction === "asc" ? result : -result;
} else {
const dateA =
a.date && a.date !== "Unknown" ? parseISO(a.date) : new Date(0);
const dateB =
b.date && b.date !== "Unknown" ? parseISO(b.date) : new Date(0);
if (!isValid(dateA) && !isValid(dateB)) return 0;
if (!isValid(dateA)) return direction === "asc" ? -1 : 1;
if (!isValid(dateB)) return direction === "asc" ? 1 : -1;
return direction === "asc"
? dateA.getTime() - dateB.getTime()
: dateB.getTime() - dateA.getTime();
}
});
},
[bookmarkedItems, sortOption],
);
const filterAndSortItems = useCallback(() => {
let filtered = [...initialItems];
if (debouncedSearchQuery) {
const lowercaseQuery = debouncedSearchQuery.toLowerCase();
filtered = filtered.filter(
(item) =>
(item.name?.toLowerCase() || "").includes(lowercaseQuery) ||
(item.description?.toLowerCase() || "").includes(lowercaseQuery),
);
}
if (selectedCategories.length > 0) {
filtered = filtered.filter((item) =>
selectedCategories.includes(item.category),
);
}
const sortedItems = sortItems(filtered);
setFilteredItems(sortedItems);
setCurrentPage(1);
}, [initialItems, debouncedSearchQuery, selectedCategories, sortItems]);
// Update filteredItems when initialItems change
useEffect(() => {
setFilteredItems(initialItems);
setCurrentPage(1);
}, [initialItems]);
useEffect(() => {
filterAndSortItems();
}, [filterAndSortItems]);
useEffect(() => {
const timer = setTimeout(() => {
setIsLoading(false);
filterAndSortItems();
}, 100);
return () => clearTimeout(timer);
}, []);
// Set loading to false when initialItems are available
useEffect(() => {
if (initialItems.length > 0) {
setIsLoading(false);
}
}, [initialItems]);
const totalPages = Math.ceil(filteredItems.length / itemsPerPage);
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = filteredItems.slice(indexOfFirstItem, indexOfLastItem);
const handlePageChange = useCallback((pageNumber: number) => {
setCurrentPage(pageNumber);
}, []);
const handleItemsPerPageChange = useCallback((value: string) => {
setItemsPerPage(Number(value));
setCurrentPage(1);
}, []);
const handleSortChange = useCallback(
(option: SortOption) => {
setSortOption(option);
const sorted = sortItems(
filteredItems.filter((item) => {
if (
selectedCategories.length > 0 &&
!selectedCategories.includes(item.category)
) {
return false;
}
if (debouncedSearchQuery) {
const lowercaseQuery = debouncedSearchQuery.toLowerCase();
return (
(item.name?.toLowerCase() || "").includes(lowercaseQuery) ||
(item.description?.toLowerCase() || "").includes(lowercaseQuery)
);
}
return true;
}),
);
setFilteredItems(sorted);
},
[filteredItems, sortItems, selectedCategories, debouncedSearchQuery],
);
// Get grid column classes
const getGridClasses = useCallback(() => {
return "sm:grid-cols-2 lg:grid-cols-3";
}, []);
// Get item card height
const getCardHeightClass = useCallback(() => {
return "min-h-[250px]";
}, []);
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
return (
{isLoading ? (
{[...Array(itemsPerPage)].map((_, index) => (
))}
) : (
)}
{filteredItems.length > 0 && (
)}
Showing {indexOfFirstItem + 1} -{" "}
{Math.min(indexOfLastItem, filteredItems.length)} of{" "}
{filteredItems.length} items
);
}
================================================
FILE: src/components/sections/sponsorship.tsx
================================================
"use client";
import { Button } from "@/components/ui/button";
import {
Marquee,
MarqueeContent,
MarqueeEdge,
MarqueeItem,
} from "@/components/ui/marquee";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { motion } from "motion/react";
import { Plus } from "lucide-react";
import { sponsors } from "@/components/sponsors/sponsors";
export function Sponsorship() {
return (
Sponsored by
);
}
================================================
FILE: src/components/sort.tsx
================================================
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { Calendar, SortAsc, SortDesc, Text } from "lucide-react";
export type SortOption = "date-desc" | "date-asc" | "name-asc" | "name-desc";
interface SortProps {
sortOption: SortOption;
onSortChange: (option: SortOption) => void;
className?: string;
}
export default function Sort({ sortOption, onSortChange, className }: SortProps) {
const sortOptions = [
{
value: "date-desc",
label: "Date (Newest first)",
icon: ,
directionIcon: ,
},
{
value: "date-asc",
label: "Date (Oldest first)",
icon: ,
directionIcon: ,
},
{
value: "name-asc",
label: "Name (A-Z)",
icon: ,
directionIcon: ,
},
{
value: "name-desc",
label: "Name (Z-A)",
icon: ,
directionIcon: ,
},
] as const;
const selectedOption =
sortOptions.find((option) => option.value === sortOption) || sortOptions[0];
const handleSortChange = (value: string) => {
onSortChange(value as SortOption);
};
return (
);
}
================================================
FILE: src/components/sponsor-card.tsx
================================================
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { ArrowRight, ExternalLink } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Sponsor } from "@/components/sponsors/sponsors";
import { motion } from "motion/react";
import React from "react";
const standardAnimations = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
transition: { duration: 0.2, ease: "easeOut" },
};
interface SponsorCardProps {
sponsor: Sponsor;
}
const SponsorCard: React.FC = ({ sponsor }) => {
const handleCardClick = () => {
window.open(sponsor.url, "_blank", "noopener,noreferrer");
};
return (
{sponsor.name}
{sponsor.description}
);
};
export default SponsorCard;
================================================
FILE: src/components/sponsors/shadcn-blocks-logo.tsx
================================================
import * as React from "react";
interface ShadcnBlocksLogoProps {
className?: string;
}
function ShadcnBlocksLogo({ className = "w-5 h-5" }: ShadcnBlocksLogoProps) {
return (
);
}
export default ShadcnBlocksLogo;
================================================
FILE: src/components/sponsors/shadcn-studio-logo.tsx
================================================
import * as React from "react";
interface ShadcnStudioLogoProps {
className?: string;
}
function ShadcnStudioLogo({ className = "w-5 h-5" }: ShadcnStudioLogoProps) {
return (
);
}
export default ShadcnStudioLogo;
================================================
FILE: src/components/sponsors/shadcn-ui-kit-logo.tsx
================================================
import * as React from "react";
import Image from "next/image";
interface ShadcnUiKitLogoProps {
className?: string;
}
function ShadcnUiKitLogo({ className = "w-5 h-5" }: ShadcnUiKitLogoProps) {
return (
);
}
export default ShadcnUiKitLogo;
================================================
FILE: src/components/sponsors/sponsors.tsx
================================================
import { ReactNode } from "react";
import ShadcnStudioLogo from "./shadcn-studio-logo";
import ShadcnBlocksLogo from "./shadcn-blocks-logo";
import ShadcnUiKitLogo from "./shadcn-ui-kit-logo";
export interface Sponsor {
name: string;
description: string;
url: string;
LogoComponent: ReactNode;
}
export const sponsors: Sponsor[] = [
{
name: "shadcnstudio.com",
description: "shadcn blocks & templates",
url: "https://shadcnstudio.com/?utm_source=awesome-shadcn-ui&utm_medium=banner&utm_campaign=github",
LogoComponent: ,
},
{
name: "shadcnblocks.com",
description: "UI blocks for your next project",
url: "https://www.shadcnblocks.com/?utm_source=awesome-shadcn-ui&utm_medium=banner&utm_campaign=github",
LogoComponent: ,
},
{
name: "shadcnuikit.com",
description: "Build faster with pre-built assets",
url: "https://shadcnuikit.com/?utm_source=awesome-shadcn-ui&utm_medium=banner&utm_campaign=github",
LogoComponent: ,
},
];
================================================
FILE: src/components/theme-toggle.tsx
================================================
"use client";
import * as React from "react";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export function ModeToggle() {
const { setTheme } = useTheme();
return (
setTheme("light")}>
Light
setTheme("dark")}>
Dark
setTheme("system")}>
System
);
}
================================================
FILE: src/components/ui/accordion.tsx
================================================
"use client"
import * as React from "react"
import { Accordion as AccordionPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
function Accordion({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AccordionItem({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps) {
return (
{children}
)
}
function AccordionContent({
className,
children,
...props
}: React.ComponentProps) {
return (
{children}
)
}
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
================================================
FILE: src/components/ui/alert-dialog.tsx
================================================
"use client"
import * as React from "react"
import { AlertDialog as AlertDialogPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
function AlertDialog({
...props
}: React.ComponentProps) {
return
}
function AlertDialogTrigger({
...props
}: React.ComponentProps) {
return (
)
}
function AlertDialogPortal({
...props
}: React.ComponentProps) {
return (
)
}
function AlertDialogOverlay({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AlertDialogContent({
className,
size = "default",
...props
}: React.ComponentProps & {
size?: "default" | "sm"
}) {
return (
)
}
function AlertDialogHeader({
className,
...props
}: React.ComponentProps<"div">) {
return (
)
}
function AlertDialogFooter({
className,
...props
}: React.ComponentProps<"div">) {
return (
)
}
function AlertDialogMedia({
className,
...props
}: React.ComponentProps<"div">) {
return (
)
}
function AlertDialogTitle({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AlertDialogDescription({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AlertDialogAction({
className,
variant = "default",
size = "default",
...props
}: React.ComponentProps &
Pick, "variant" | "size">) {
return (
)
}
function AlertDialogCancel({
className,
variant = "outline",
size = "default",
...props
}: React.ComponentProps &
Pick, "variant" | "size">) {
return (
)
}
export {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogMedia,
AlertDialogOverlay,
AlertDialogPortal,
AlertDialogTitle,
AlertDialogTrigger,
}
================================================
FILE: src/components/ui/alert.tsx
================================================
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const alertVariants = cva(
"grid gap-0.5 rounded-none border px-2.5 py-2 text-left text-xs has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert",
{
variants: {
variant: {
default: "bg-card text-card-foreground",
destructive:
"text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Alert({
className,
variant,
...props
}: React.ComponentProps<"div"> & VariantProps) {
return (
)
}
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3",
className
)}
{...props}
/>
)
}
function AlertDescription({
className,
...props
}: React.ComponentProps<"div">) {
return (
)
}
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
return (
)
}
export { Alert, AlertTitle, AlertDescription, AlertAction }
================================================
FILE: src/components/ui/aspect-ratio.tsx
================================================
"use client"
import { AspectRatio as AspectRatioPrimitive } from "radix-ui"
function AspectRatio({
...props
}: React.ComponentProps
) {
return
}
export { AspectRatio }
================================================
FILE: src/components/ui/avatar.tsx
================================================
"use client"
import * as React from "react"
import { Avatar as AvatarPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
function Avatar({
className,
size = "default",
...props
}: React.ComponentProps & {
size?: "default" | "sm" | "lg"
}) {
return (
)
}
function AvatarImage({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AvatarFallback({
className,
...props
}: React.ComponentProps) {
return (
)
}
function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) {
return (
svg]:hidden",
"group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2",
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2",
className
)}
{...props}
/>
)
}
function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
)
}
function AvatarGroupCount({
className,
...props
}: React.ComponentProps<"div">) {
return (
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3",
className
)}
{...props}
/>
)
}
export {
Avatar,
AvatarImage,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
AvatarBadge,
}
================================================
FILE: src/components/ui/badge.tsx
================================================
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
const badgeVariants = cva(
"h-5 gap-1 rounded-none border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive overflow-hidden group/badge",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
secondary:
"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
destructive:
"bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
outline:
"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
ghost:
"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
link: "text-primary underline-offset-4 hover:underline",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Badge({
className,
variant = "default",
asChild = false,
...props
}: React.ComponentProps<"span"> &
VariantProps
& { asChild?: boolean }) {
const Comp = asChild ? Slot.Root : "span"
return (
)
}
export { Badge, badgeVariants }
================================================
FILE: src/components/ui/breadcrumb.tsx
================================================
import * as React from "react"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
return (
)
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
return (
)
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
return (
)
}
function BreadcrumbLink({
asChild,
className,
...props
}: React.ComponentProps<"a"> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot.Root : "a"
return (
)
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
)
}
function BreadcrumbSeparator({
children,
className,
...props
}: React.ComponentProps<"li">) {
return (
svg]:size-3.5", className)}
{...props}
>
{children ?? (
)}
)
}
function BreadcrumbEllipsis({
className,
...props
}: React.ComponentProps<"span">) {
return (
svg]:size-4",
className
)}
{...props}
>
More
)
}
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
}
================================================
FILE: src/components/ui/button-group.tsx
================================================
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"
const buttonGroupVariants = cva(
"rounded-none has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-none flex w-fit items-stretch *:focus-visible:z-10 *:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
{
variants: {
orientation: {
horizontal:
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
vertical:
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
},
},
defaultVariants: {
orientation: "horizontal",
},
}
)
function ButtonGroup({
className,
orientation,
...props
}: React.ComponentProps<"div"> & VariantProps) {
return (
)
}
function ButtonGroupText({
className,
asChild = false,
...props
}: React.ComponentProps<"div"> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot.Root : "div"
return (
)
}
function ButtonGroupSeparator({
className,
orientation = "vertical",
...props
}: React.ComponentProps) {
return (
)
}
export {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
buttonGroupVariants,
}
================================================
FILE: src/components/ui/button.tsx
================================================
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-none border border-transparent bg-clip-padding text-xs font-medium focus-visible:ring-1 aria-invalid:ring-1 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
outline:
"border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost:
"hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
destructive:
"bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default:
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
xs: "h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
sm: "h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
icon: "size-8",
"icon-xs": "size-6 rounded-none [&_svg:not([class*='size-'])]:size-3",
"icon-sm": "size-7 rounded-none",
"icon-lg": "size-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
function Button({
className,
variant = "default",
size = "default",
asChild = false,
...props
}: React.ComponentProps<"button"> &
VariantProps & {
asChild?: boolean
}) {
const Comp = asChild ? Slot.Root : "button"
return (
)
}
export { Button, buttonVariants }
================================================
FILE: src/components/ui/calendar.tsx
================================================
"use client"
import * as React from "react"
import {
DayPicker,
getDefaultClassNames,
type DayButton,
type Locale,
} from "react-day-picker"
import { cn } from "@/lib/utils"
import { Button, buttonVariants } from "@/components/ui/button"
import { ChevronLeftIcon, ChevronRightIcon, ChevronDownIcon } from "lucide-react"
function Calendar({
className,
classNames,
showOutsideDays = true,
captionLayout = "label",
buttonVariant = "ghost",
locale,
formatters,
components,
...props
}: React.ComponentProps & {
buttonVariant?: React.ComponentProps["variant"]
}) {
const defaultClassNames = getDefaultClassNames()
return (
svg]:rotate-180`,
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
className
)}
captionLayout={captionLayout}
locale={locale}
formatters={{
formatMonthDropdown: (date) =>
date.toLocaleString(locale?.code, { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
months: cn(
"flex gap-4 flex-col md:flex-row relative",
defaultClassNames.months
),
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
nav: cn(
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
defaultClassNames.nav
),
button_previous: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_previous
),
button_next: cn(
buttonVariants({ variant: buttonVariant }),
"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none",
defaultClassNames.button_next
),
month_caption: cn(
"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)",
defaultClassNames.month_caption
),
dropdowns: cn(
"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5",
defaultClassNames.dropdowns
),
dropdown_root: cn(
"relative rounded-(--cell-radius)",
defaultClassNames.dropdown_root
),
dropdown: cn(
"absolute bg-popover inset-0 opacity-0",
defaultClassNames.dropdown
),
caption_label: cn(
"select-none font-medium",
captionLayout === "label"
? "text-sm"
: "rounded-(--cell-radius) flex items-center gap-1 text-sm [&>svg]:text-muted-foreground [&>svg]:size-3.5",
defaultClassNames.caption_label
),
table: "w-full border-collapse",
weekdays: cn("flex", defaultClassNames.weekdays),
weekday: cn(
"text-muted-foreground rounded-(--cell-radius) flex-1 font-normal text-[0.8rem] select-none",
defaultClassNames.weekday
),
week: cn("flex w-full mt-2", defaultClassNames.week),
week_number_header: cn(
"select-none w-(--cell-size)",
defaultClassNames.week_number_header
),
week_number: cn(
"text-[0.8rem] select-none text-muted-foreground",
defaultClassNames.week_number
),
day: cn(
"relative w-full rounded-(--cell-radius) h-full p-0 text-center [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius) group/day aspect-square select-none",
props.showWeekNumber
? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)"
: "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
defaultClassNames.day
),
range_start: cn(
"rounded-l-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:right-0 z-0 isolate",
defaultClassNames.range_start
),
range_middle: cn("rounded-none", defaultClassNames.range_middle),
range_end: cn(
"rounded-r-(--cell-radius) bg-muted relative after:bg-muted after:absolute after:inset-y-0 after:w-4 after:left-0 z-0 isolate",
defaultClassNames.range_end
),
today: cn(
"bg-muted text-foreground rounded-(--cell-radius) data-[selected=true]:rounded-none",
defaultClassNames.today
),
outside: cn(
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside
),
disabled: cn(
"text-muted-foreground opacity-50",
defaultClassNames.disabled
),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
Root: ({ className, rootRef, ...props }) => {
return (
)
},
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
)
}
if (orientation === "right") {
return (
)
}
return (
)
},
DayButton: ({ ...props }) => (
),
WeekNumber: ({ children, ...props }) => {
return (
{children}
|
)
},
...components,
}}
{...props}
/>
)
}
function CalendarDayButton({
className,
day,
modifiers,
locale,
...props
}: React.ComponentProps & { locale?: Partial }) {
const defaultClassNames = getDefaultClassNames()
const ref = React.useRef(null)
React.useEffect(() => {
if (modifiers.focused) ref.current?.focus()
}, [modifiers.focused])
return (