Amins Essential React Components & Hooks - shadcn/ui Registry

September 18, 2025 (3d ago)

Building Better React Apps: A Complete Guide to Custom shadcn/ui Components and Hooks

React development often involves repetitive patterns and boilerplate code. What if you could streamline your workflow with a collection of reusable components and hooks that handle common UI patterns and state management? Today, I'm excited to share a comprehensive registry of custom shadcn/ui components and hooks that will supercharge your React development.

What's in This Registry?

This registry contains 15 carefully crafted utilities split into two categories:

  • 8 Utility Components for rendering logic and UI patterns
  • 8 Custom Hooks for state management and browser interactions

All components are built with TypeScript, follow React best practices, and integrate seamlessly with the shadcn/ui ecosystem.

🚀 Quick Setup (Recommended)

For the best experience, configure the registry namespace in your components.json:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.js",
    "css": "app/globals.css",
    "baseColor": "slate",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "hooks": "@/hooks"
  },
  "registries": {
    "@amin": "https://aminahmady.vercel.app/r/{name}.json"
  }
}

Then install any component using:

pnpm dlx shadcn@latest add @amin/[component-name]

🧩 Utility Components

1. Condition - Smart Conditional Rendering

The Condition component provides an elegant way to handle complex conditional rendering scenarios, similar to switch statements but more React-friendly.

import { Condition, If, ElseIf, Else } from "@/components/ui/condition"
 
function UserStatus({ user }) {
  return (
    <Condition>
      <If condition={user.isAdmin}>
        <AdminPanel />
      </If>
      <ElseIf condition={user.isPremium}>
        <PremiumFeatures />
      </ElseIf>
      <Else>
        <BasicFeatures />
      </Else>
    </Condition>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/condition
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/condition.json

Key Features:

  • Declarative conditional rendering
  • Multiple condition support with ElseIf
  • Fallback content with Else
  • Type-safe props

2. Show - Simple Conditional Display

For straightforward show/hide logic, the Show component offers a clean alternative to ternary operators.

import { Show } from "@/components/ui/show"
 
function Notification({ hasError, message }) {
  return (
    <Show show={hasError}>
      <Alert variant="destructive">{message}</Alert>
    </Show>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/show
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/show.json

3. For - Declarative List Rendering

The For component makes list rendering more readable and handles edge cases like empty arrays.

import { For } from "@/components/ui/for"
 
function TodoList({ todos }) {
  return (
    <For 
      each={todos} 
      fallback={<p>No todos yet!</p>}
    >
      {(todo, index) => (
        <TodoItem key={todo.id} todo={todo} index={index} />
      )}
    </For>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/for
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/for.json

Features:

  • Generic type support
  • Fallback content for empty arrays
  • Index access in render function

4. Switch/Case - Pattern Matching

Handle multiple conditions elegantly with the Switch and Case components.

import { Switch, Case, Default } from "@/components/ui/switch-case"
 
function StatusBadge({ status }) {
  return (
    <Switch value={status}>
      <Case value="pending">
        <Badge variant="secondary">Pending</Badge>
      </Case>
      <Case value="approved">
        <Badge variant="success">Approved</Badge>
      </Case>
      <Case value="rejected">
        <Badge variant="destructive">Rejected</Badge>
      </Case>
      <Default>
        <Badge variant="outline">Unknown</Badge>
      </Default>
    </Switch>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/switch-case
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/switch-case.json

5. While - Loop Component

For dynamic content generation based on conditions:

import { While } from "@/components/ui/while"
 
function Countdown({ seconds }) {
  return (
    <While condition={() => seconds > 0} maxIterations={60}>
      {(iteration) => <div>Time remaining: {seconds - iteration}</div>}
    </While>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/while
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/while.json

6. DoWhile - Do-While Loop Component

For loops that execute at least once:

import { DoWhile } from "@/components/ui/do-while"
 
function LoadingDots() {
  return (
    <DoWhile condition={true} maxIterations={3}>
      {(iteration) => <span key={iteration}>.</span>}
    </DoWhile>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/do-while
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/do-while.json

7. Switcher - Binary State Toggle

Perfect for toggling between two different UI states:

import { Switcher } from "@/components/ui/switcher"
 
function ViewToggle({ isGridView }) {
  return (
    <Switcher next={isGridView}>
      <ListView key="list" />
      <GridView key="grid" />
    </Switcher>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/switcher
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/switcher.json

8. VisuallyHidden - Accessibility Component

Built on Radix UI primitives for hiding content visually while keeping it accessible to screen readers:

import { VisuallyHidden } from "@/components/ui/visually-hidden"
 
function IconButton({ icon, label }) {
  return (
    <button>
      {icon}
      <VisuallyHidden>{label}</VisuallyHidden>
    </button>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/visually-hidden
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/visually-hidden.json

🎣 Custom Hooks

1. useBoolean - Boolean State Management

Simplify boolean state with convenient helper methods:

import { useBoolean } from "@/hooks/use-boolean"
 
function Modal() {
  const { value: isOpen, setTrue: open, setFalse: close, toggle } = useBoolean()
  
  return (
    <>
      <Button onClick={open}>Open Modal</Button>
      <Dialog open={isOpen} onOpenChange={close}>
        {/* Modal content */}
      </Dialog>
    </>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-boolean
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-boolean.json

Features:

  • setTrue(), setFalse(), toggle() helpers
  • Type-safe boolean operations
  • Memoized callbacks for performance

2. useCounter - Numeric State Management

Perfect for counters, pagination, and numeric controls:

import { useCounter } from "@/hooks/use-counter"
 
function LikeButton() {
  const { count, increment, decrement, reset } = useCounter(0)
  
  return (
    <div>
      <Button onClick={decrement}>-</Button>
      <span>{count}</span>
      <Button onClick={increment}>+</Button>
      <Button onClick={reset}>Reset</Button>
    </div>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-counter
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-counter.json

3. useCountdown - Timer Functionality

Build timers and countdown features easily:

import { useCountdown } from "@/hooks/use-countdown"
 
function CountdownTimer() {
  const [count, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({
    countStart: 60,
    countStop: 0,
    intervalMs: 1000
  })
  
  return (
    <div>
      <div>Time: {count}s</div>
      <Button onClick={startCountdown}>Start</Button>
      <Button onClick={stopCountdown}>Stop</Button>
      <Button onClick={resetCountdown}>Reset</Button>
    </div>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-countdown
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-countdown.json

Features:

  • Configurable intervals
  • Start/stop/reset controls
  • Increment or decrement modes
  • Custom stop conditions

4. useEventListener - Event Management

Type-safe event listeners with automatic cleanup:

import { useEventListener } from "@/hooks/use-event-listener"
 
function KeyboardShortcuts() {
  useEventListener('keydown', (event) => {
    if (event.ctrlKey && event.key === 's') {
      event.preventDefault()
      saveDocument()
    }
  })
  
  return <div>Press Ctrl+S to save</div>
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-event-listener
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-event-listener.json

5. useInterval - Timer Hook

Manage intervals with React lifecycle integration:

import { useInterval } from "@/hooks/use-interval"
 
function LiveClock() {
  const [time, setTime] = useState(new Date())
  
  useInterval(() => {
    setTime(new Date())
  }, 1000)
  
  return <div>{time.toLocaleTimeString()}</div>
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-interval
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-interval.json

6. useIsMobile - Responsive Design

Detect mobile devices and respond to viewport changes:

import { useIsMobile } from "@/hooks/use-mobile"
 
function ResponsiveLayout() {
  const isMobile = useIsMobile()
  
  return isMobile ? <MobileLayout /> : <DesktopLayout />
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-mobile
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-mobile.json

7. useScript - Dynamic Script Loading

Load external scripts dynamically:

import { useScript } from "@/hooks/use-script"
 
function GoogleMaps() {
  useScript(
    'https://maps.googleapis.com/maps/api/js?key=YOUR_KEY',
    'head',
    { async: true }
  )
  
  return <div id="map">Loading map...</div>
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-script
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-script.json

8. useIsMounted - Mount State Detection

Check if a component is mounted to prevent state updates on unmounted components (SSR-safe):

import { useIsMounted } from "@/hooks/use-is-mounted"
 
function ConditionalComponent() {
  const isMounted = useIsMounted()
  
  if (!isMounted) return <div>Loading...</div>
  
  return <div>Component is mounted and ready!</div>
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-is-mounted
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-is-mounted.json

9. useIsomorphicLayoutEffect - SSR-Safe Layout Effect

A drop-in replacement for useLayoutEffect that works safely in SSR environments:

import { useIsomorphicLayoutEffect } from "@/hooks/use-isomorphic-layout-effect"
 
function DOMManipulation() {
  const ref = useRef<HTMLDivElement>(null)
  
  useIsomorphicLayoutEffect(() => {
    if (ref.current) {
      // Safe DOM manipulation
      ref.current.style.height = '100px'
    }
  }, [])
  
  return <div ref={ref}>Styled element</div>
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-isomorphic-layout-effect
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-isomorphic-layout-effect.json

10. useSsr - Environment Detection

Detect server/client environment for conditional rendering:

import { useSsr } from "@/hooks/use-ssr"
 
function EnvironmentAwareComponent() {
  const { isBrowser, isServer } = useSsr()
  
  return (
    <div>
      {isBrowser && <ClientOnlyFeature />}
      {isServer && <ServerOnlyContent />}
    </div>
  )
}

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-ssr
 
# Or direct URL
npx shadcn@latest add https://aminahmady.vercel.app/r/use-ssr.json

Installation:

# Using namespace (recommended)
pnpm dlx shadcn@latest add @amin/use-is-mounted
pnpm dlx shadcn@latest add @amin/use-isomorphic-layout-effect
pnpm dlx shadcn@latest add @amin/use-ssr
 
# Or direct URLs
npx shadcn@latest add https://aminahmady.vercel.app/r/use-is-mounted.json
npx shadcn@latest add https://aminahmady.vercel.app/r/use-isomorphic-layout-effect.json
npx shadcn@latest add https://aminahmady.vercel.app/r/use-ssr.json

🚀 Installation & Setup

Prerequisites

Make sure you have shadcn/ui set up in your project:

npx shadcn-ui@latest init

Adding Components to Your Project

You can add these components to your project using the shadcn CLI in two ways: direct URL installation or by configuring a custom registry namespace.

Prerequisites

Make sure you have shadcn/ui set up in your project:

npx shadcn@latest init

🎯 Best Practices

1. Type Safety

All components and hooks are built with TypeScript and provide full type safety:

// Type-safe iteration
<For each={users}>
  {(user) => <UserCard user={user} />}  // user is properly typed
</For>

2. Performance Optimization

Hooks use useCallback and useMemo where appropriate to prevent unnecessary re-renders:

const { toggle } = useBoolean()  // toggle is memoized

3. Accessibility

Components like VisuallyHidden ensure your app remains accessible:

<Button>
  <Icon />
  <VisuallyHidden>Save document</VisuallyHidden>
</Button>

4. SSR Compatibility

All hooks handle server-side rendering gracefully:

const { isBrowser, isServer } = useSsr()
// Safe to use in Next.js, Remix, etc.

🔧 Customization

Extending Components

All components accept standard React props and can be easily extended:

// Custom styling
<Show show={isVisible} className="animate-fade-in">
  <Alert>Custom styled alert</Alert>
</Show>
 
// Adding custom logic
const CustomFor = ({ children, each, sortBy }) => {
  const sortedItems = useMemo(() => 
    sortBy ? [...each].sort(sortBy) : each, [each, sortBy]
  )
  
  return <For each={sortedItems}>{children}</For>
}

Hook Composition

Combine hooks for complex state management:

function useToggleCounter() {
  const { value: isEnabled, toggle } = useBoolean()
  const { count, increment, reset } = useCounter()
  
  const incrementIfEnabled = useCallback(() => {
    if (isEnabled) increment()
  }, [isEnabled, increment])
  
  return { isEnabled, toggle, count, incrementIfEnabled, reset }
}

🚦 Migration Guide

From Standard React Patterns

Before:

{items.length > 0 ? (
  items.map((item, index) => (
    <Item key={item.id} item={item} />
  ))
) : (
  <EmptyState />
)}

After:

<For each={items} fallback={<EmptyState />}>
  {(item, index) => <Item key={item.id} item={item} />}
</For>

Before:

const [isOpen, setIsOpen] = useState(false)
const open = () => setIsOpen(true)
const close = () => setIsOpen(false)

After:

const { value: isOpen, setTrue: open, setFalse: close } = useBoolean()

🎉 Conclusion

This registry provides a solid foundation for building React applications with better developer experience and cleaner code. Each component and hook solves real-world problems while maintaining the flexibility and composability that makes React great.

Key Benefits:

  • 🎯 Focused: Each utility has a single responsibility
  • 🔒 Type-Safe: Full TypeScript support
  • ♿ Accessible: Built with accessibility in mind
  • 🚀 Performance: Optimized for React's rendering cycle
  • 🔧 Flexible: Easy to customize and extend
  • 📱 Responsive: Mobile and SSR ready

Start small by adding just the components you need, and gradually build up your custom UI library. Your future self (and your team) will thank you for the cleaner, more maintainable code.


Ready to supercharge your React development? Pick a component, install it, and start building better UIs today!

📚 Additional Resources


Tags: #React #TypeScript #shadcn #UI #Components #Hooks #Frontend #WebDevelopment