shadcn-ui/ui · error · Error

useCarousel must be used within a <Carousel />

Error message

useCarousel must be used within a <Carousel />

What it means

useCarousel reads React.useContext(CarouselContext). The only code that ever puts a non-null value into that context is <Carousel>, which renders <CarouselContext.Provider value={...}> around its children. If a component calls useCarousel (directly or through CarouselContent / CarouselPrevious / CarouselNext / CarouselDots, which all call it) without a <Carousel> ancestor, context resolves to null and the hook throws to fail fast instead of returning a half-formed API.

Source

Thrown at apps/v4/registry/bases/radix/ui/carousel.tsx:39

  setApi?: (api: CarouselApi) => void
}

type CarouselContextProps = {
  carouselRef: ReturnType<typeof useEmblaCarousel>[0]
  api: ReturnType<typeof useEmblaCarousel>[1]
  scrollPrev: () => void
  scrollNext: () => void
  canScrollPrev: boolean
  canScrollNext: boolean
} & CarouselProps

const CarouselContext = React.createContext<CarouselContextProps | null>(null)

function useCarousel() {
  const context = React.useContext(CarouselContext)

  if (!context) {
    throw new Error("useCarousel must be used within a <Carousel />")
  }

  return context
}

function Carousel({
  orientation = "horizontal",
  opts,
  setApi,
  plugins,
  className,
  children,
  ...props
}: React.ComponentProps<"div"> & CarouselProps) {
  const [carouselRef, api] = useEmblaCarousel(
    {
      ...opts,
      axis: orientation === "horizontal" ? "x" : "y",

View on GitHub (pinned to efac598707)

Solutions

  1. Wrap the offending subtree in <Carousel opts={...}>...</Carousel> so the provider is an ancestor.
  2. Move the component that calls useCarousel back inside the <Carousel> tree.
  3. For isolated tests/stories, render the sub-component inside a <Carousel> rather than bare.

Example fix

// before
<CarouselPrevious />

// after
<Carousel>
  <CarouselContent>
    <CarouselItem>...</CarouselItem>
  </CarouselContent>
  <CarouselPrevious />
</Carousel>
Defensive patterns

Strategy: validation

Validate before calling

// Optional, non-throwing reader — call before relying on the hook
import { carouselContext } from "./carousel" // or re-create the context ref
function useOptionalCarousel() {
  return React.useContext(CarouselContext)
}
// guard at call site:
const ctx = useOptionalCarousel()
if (!ctx) return null

Type guard

// True when a <Carousel> ancestor is present
function useHasCarousel(): boolean {
  return React.useContext(CarouselContext) !== null
}

Prevention

When it happens

Trigger: Rendering any carousel sub-component (CarouselItem, CarouselContent, CarouselPrevious, CarouselNext) outside of a <Carousel> wrapper; copy-pasting only the inner markup; conditionally unmounting <Carousel> while keeping its children mounted; importing useCarousel in a standalone control.

Common situations: Extracting a carousel control into its own file and forgetting the wrapper; Storybook stories that render a single CarouselItem in isolation; refactors that lift children above the <Carousel> node.

Related errors


AI-assisted analysis of shadcn-ui/ui@efac598707 (2026-08-12). Data as JSON: /api/errors/1a2abc4c932982f8. Report an issue: GitHub.