shadcn-ui/ui · error · Error

useBlockViewer must be used within a BlockViewerProvider.

Error message

useBlockViewer must be used within a BlockViewerProvider.

What it means

`useBlockViewer` reads `BlockViewerContext` (`createContext<BlockViewerContext | null>(null)`). `BlockViewerProvider` supplies `item`, `tree`, `highlightedFiles`, plus state (`iframeKey`, etc.). Any consumer for which `useContext` returns null throws — the block viewer sub-components (file tree, code view, iframe) all assume these props exist.

Source

Thrown at apps/v4/components/block-viewer.tsx:87

  activeFile: string | null
  setActiveFile: (file: string) => void
  resizablePanelRef: React.RefObject<PanelImperativeHandle | null> | null
  tree: ReturnType<typeof createFileTreeForRegistryItemFiles> | null
  highlightedFiles:
    | (z.infer<typeof registryItemFileSchema> & {
        highlightedContent: string
      })[]
    | null
  iframeKey?: number
  setIframeKey?: React.Dispatch<React.SetStateAction<number>>
}

const BlockViewerContext = React.createContext<BlockViewerContext | null>(null)

function useBlockViewer() {
  const context = React.useContext(BlockViewerContext)
  if (!context) {
    throw new Error("useBlockViewer must be used within a BlockViewerProvider.")
  }
  return context
}

function BlockViewerProvider({
  item,
  tree,
  highlightedFiles,
  children,
}: Pick<BlockViewerContext, "item" | "tree" | "highlightedFiles"> & {
  children: React.ReactNode
}) {
  const [view, setView] = React.useState<BlockViewerContext["view"]>("preview")
  const [activeFile, setActiveFile] = React.useState<
    BlockViewerContext["activeFile"]
  >(highlightedFiles?.[0].target ?? null)
  const resizablePanelRef = React.useRef<PanelImperativeHandle>(null)
  const [iframeKey, setIframeKey] = React.useState(0)

View on GitHub (pinned to efac598707)

Solutions

  1. Always mount `<BlockViewerProvider item tree highlightedFiles>` above any sub-component that calls `useBlockViewer()`.
  2. Pass the required props (`item`, `tree`, `highlightedFiles`) to the provider — it does not default them.
  3. In tests/stories, render the whole `<BlockViewerProvider>` wrapper with stub props.

Example fix

// before
<BlockViewerFiles />

// after
<BlockViewerProvider item={item} tree={tree} highlightedFiles={files}>
  <BlockViewerFiles />
</BlockViewerProvider>
Defensive patterns

Strategy: type-guard

Validate before calling

render(<BlockViewerProvider item={stubItem} tree={stubTree} highlightedFiles={stubFiles}>{<BlockViewerFiles/>}</BlockViewerProvider>)

Type guard

import React from "react"
import { BlockViewerContext } from "@/components/block-viewer"
const hasBlockViewer = () => React.useContext(BlockViewerContext) != null

Try / catch

try { useBlockViewer() } catch (e) { if (e.message.includes("BlockViewerProvider")) {/*mount with required props*/} throw e }

Prevention

When it happens

Trigger: Rendering a block-viewer child (e.g. `<BlockViewerFiles />`, `<BlockViewerIframe />`) outside `<BlockViewerProvider item={...} tree={...} highlightedFiles={...}>`. Common when composing the viewer from parts without the provider, or rendering a single part in isolation.

Common situations: Splitting the block viewer into composable parts; rendering a part inside a portal detached from the provider tree; storybook stories of individual parts.

Related errors


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