shadimage
corecn
componentcomplex-componentsource: ok · hit

Complex Component

A complex component showing hooks, libs and components.

npx shadcn add "https://corecn.vercel.app/r/complex-component.json"
free

No selection tags yet — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light

Registry dependencies

card

Files5 · source cached 10/14/2026, 3:39:09 PM

registry/corecn/blocks/complex-component/page.tsx
import { cache } from "react"
import { PokemonCard } from "@/registry/corecn/blocks/complex-component/components/pokemon-card"
import { getPokemonList } from "@/registry/corecn/blocks/complex-component/lib/pokemon"
const getCachedPokemonList = cache(getPokemonList)

export default async function Page() {
  const pokemons = await getCachedPokemonList({ limit: 12 })

  if (!pokemons) {
    return null
  }

  return (
    <div className="mx-auto w-full max-w-2xl px-4">
      <div className="grid grid-cols-2 gap-4 py-10 sm:grid-cols-3 md:grid-cols-4">
        {pokemons.results.map((p) => (
          <PokemonCard key={p.name} name={p.name} />
        ))}
      </div>
    </div>
  )
}
registry/corecn/blocks/complex-component/components/pokemon-card.tsx
import { cache } from "react"
import { getPokemon } from "@/registry/corecn/blocks/complex-component/lib/pokemon"
import { Card, CardContent } from "@/registry/corecn/ui/card"
import { PokemonImage } from "@/registry/corecn/blocks/complex-component/components/pokemon-image"

const cachedGetPokemon = cache(getPokemon)

export async function PokemonCard({ name }: { name: string }) {
  const pokemon = await cachedGetPokemon(name)

  if (!pokemon) {
    return null
  }

  return (
    <Card>
      <CardContent className="flex flex-col items-center p-2">
        <div>
          <PokemonImage name={pokemon.name} number={pokemon.id} />
        </div>
        <div className="text-center font-medium">{pokemon.name}</div>
      </CardContent>
    </Card>
  )
}
registry/corecn/blocks/complex-component/components/pokemon-image.tsx
"use client"

/* eslint-disable @next/next/no-img-element */
import { usePokemonImage } from "@/registry/corecn/blocks/complex-component/hooks/use-pokemon"

export function PokemonImage({
  name,
  number,
}: {
  name: string
  number: number
}) {
  const imageUrl = usePokemonImage(number)

  if (!imageUrl) {
    return null
  }

  return <img src={imageUrl} alt={name} />
}
registry/corecn/blocks/complex-component/lib/pokemon.ts
import { z } from "zod"

export async function getPokemonList({ limit = 10 }: { limit?: number }) {
  try {
    const response = await fetch(
      `https://pokeapi.co/api/v2/pokemon?limit=${limit}`
    )
    return z
      .object({
        results: z.array(z.object({ name: z.string() })),
      })
      .parse(await response.json())
  } catch (error) {
    console.error(error)
    return null
  }
}

export async function getPokemon(name: string) {
  try {
    const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`)

    if (!response.ok) {
      throw new Error("Failed to fetch pokemon")
    }

    return z
      .object({
        name: z.string(),
        id: z.number(),
        sprites: z.object({
          front_default: z.string(),
        }),
        stats: z.array(
          z.object({
            base_stat: z.number(),
            stat: z.object({
              name: z.string(),
            }),
          })
        ),
      })
      .parse(await response.json())
  } catch (error) {
    console.error(error)
    return null
  }
}
registry/corecn/blocks/complex-component/hooks/use-pokemon.ts
"use client"

// Totally unnecessary hook, but it's a good example of how to use a hook in a custom registry.

export function usePokemonImage(number: number) {
  return `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${number}.png`
}

More from corecn

Browse all components in this library →