{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "error-boundary",
  "title": "Error Boundary",
  "description": "Catches a render error from anywhere below it and shows a fallback in place of that part of the page, instead of letting React take the whole application down to a blank screen: one widget on a dashboard, a third-party embed or ad slot, a chart handed a malformed series, a route or layout boundary in a Next.js app, a single row of a list, a markdown or rich-text renderer fed user content, a map or canvas that fails on one device. Common asks it answers: \"react error boundary\", \"error boundary shadcn\", \"shadcn error boundary component\", \"react-error-boundary alternative\", \"error boundary typescript\", \"componentDidCatch in a function component\", \"error boundary hook\", \"catch an error in a react component\", \"react white screen of death\", \"one component crashes and takes the whole app down\", \"error boundary with a retry button\", \"reset error boundary on route change\", \"error boundary resetKeys\", \"resetKeys not working\", \"error boundary keeps resetting in a loop\", \"useErrorBoundary showBoundary\", \"error boundary not catching my error\", \"error boundary does not catch event handler errors\", \"error boundary async error\", \"catch a promise rejection with an error boundary\", \"next.js error.tsx alternative\", \"fallback ui when a component throws\", \"withErrorBoundary hoc\", \"エラーバウンダリ react\", \"React エラー境界\", \"画面が真っ白になる react\", \"一箇所のエラーでアプリ全体が落ちる\", \"エラー時のフォールバック表示\", \"リトライできるエラー表示\". Official shadcn/ui has nothing of the kind, and that is measured rather than remembered: its catalogue today lists 65 entries of which 62 are fetchable (code-block, questionnaire and trace 404) for 223,287 bytes of component source, and in all of it componentDidCatch, getDerivedStateFromError, ErrorBoundary, errorInfo, resetErrorBoundary and fallbackRender are every one of them zero hits. So is Suspense, and so is the word class -- official is 62 function components with no error handling anywhere in them. An agent asked for a boundary therefore writes one, and this is the one component in a modern React codebase that cannot be a function: getDerivedStateFromError and componentDidCatch have no hook equivalent, so it is a class or it does not exist. The dozen lines that class takes are not the reason to install one. Four things are. First, clearing the error is not recovering. Rendering the fallback removes the children from the tree, so React does unmount them and a reset really does mount them fresh with their state gone -- but what made them throw is usually a prop or something in a store, and that has not moved, so a retry that only clears the flag throws again on the next frame. onReset is where the caller drops the bad response or bumps the query key; resetKeys is where it says what counts as the cause having changed. Second, a reset loop is easy to write by accident, in two separate ways, and both are closed here. resetKeys is compared element by element rather than by array identity, because resetKeys={[id]} builds a fresh array on every render of the parent and an identity check reads that as a change every time -- clear, mount, throw, repeat. And the keys are snapshotted as each render sees them rather than compared against prevProps in componentDidUpdate, which is what makes the ordinary case right: when a parent passes a new id and the child chokes on that new id in the same pass, comparing with prevProps reads it as \"the keys changed while an error was showing\", resets, and lands back on the same throw one render later. A child that throws again under keys that have not moved simply stays in the fallback. Third, most of the errors in an application never reach a boundary at all, and this is the gap that makes people think theirs is broken. React catches what is thrown while it renders and nothing else, so an onClick that throws, a setTimeout, a rejected promise, a subscription callback and the server render all go straight past it and leave the user looking at a page that quietly did nothing. useErrorBoundary() returns showBoundary, which stores the value and rethrows it from that component's next render -- a real render, so the boundary catches it with a real component stack and onError reports it like any other. load().then(setData, showBoundary) is the whole pattern. Nothing has to be cleared afterwards, because the component holding it is replaced by the fallback and unmounts. Fourth, the crash takes focus with it. The element that had it is no longer in the document, so the browser drops focus to the body and a keyboard or screen-reader user is silently returned to the top of the page with no sign that anything happened. The built-in fallback takes focus back -- and only then: not when the children threw on their first render, because nothing the user was looking at went away, and not when focus is still on something real elsewhere on the page, because that belongs to whoever is using it. What it cannot do is stated rather than hidden, since a boundary that silently misses is worse than none. It cannot catch an error thrown by its own render, which includes the fallback, so a fallback that throws goes to the boundary above and keep it to markup. It does nothing on the server: componentDidCatch is a commit-phase lifecycle and the server never commits. And it does not log, because React already prints a recovered error and its component stack to the console in development and a second copy helps nobody. Smaller things it gets right. Anything can be thrown in JavaScript, so a non-Error value arrives wrapped with the original kept on cause, and a fallback reading error.message renders something rather than \"undefined\"; an Error from an iframe, a worker or a vm context fails instanceof and is matched on having a string message instead of being discarded; a thrown symbol does not become a TypeError from String() replacing the application's error with one from the boundary. onError fires once per error rather than once per commit, and again if the same error comes back after a retry. Both error.message and React's componentStack routinely carry whatever was being rendered -- an email address, an order, an id -- so treat them as user data when the destination is somebody else's service, and the built-in fallback does not show the message to the reader at all unless you ask it to. The fallback is a role=\"alert\" notice with a heading and a Try again button, announced on arrival because it arrives, focusable only programmatically so an error notice does not add a tab stop to the page, and themed through border-destructive, bg-card and the rest rather than colours of its own. Pass fallback as a node, as a function of { error, reset, recoverFocus }, or as null for a decorative widget that should just disappear; ErrorFallback is exported so a custom one can keep the same shape, and withErrorBoundary wraps a route or page component whose own file is the only place you can reach. Within pulld it is the last resort rather than the first: form-error-summary handles the errors a person can fix, network-status the connection being gone, toast and save-status the ones an operation reports, empty-state the case where there is simply nothing to show. This one is for the case nobody planned for. Depends only on your cn util -- no packages, no other components.",
  "files": [
    {
      "path": "registry/ui/error-boundary.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/** Stands in for `resetKeys` when the caller passes none, so the comparison never sees undefined. */\nconst NO_KEYS: readonly unknown[] = []\n\n/**\n * Whether two `resetKeys` lists say the same thing.\n *\n * Element-wise rather than by identity, and this is the whole difference between a boundary that\n * works and one that flaps. `resetKeys={[userId]}` builds a fresh array on every render of the\n * parent, so an identity comparison reports a change every time the parent renders — the boundary\n * clears the error, the child mounts, throws for the same reason it threw before, and the parent\n * renders again. Comparing the contents means \"changed\" means the caller changed something.\n */\nfunction sameKeys(a: readonly unknown[], b: readonly unknown[]): boolean {\n  if (a === b) return true\n  if (a.length !== b.length) return false\n  for (let i = 0; i < a.length; i++) {\n    if (!Object.is(a[i], b[i])) return false\n  }\n  return true\n}\n\n/**\n * A readable message for something thrown that was not an Error.\n *\n * `throw \"nope\"` and `throw { code: 500 }` are legal, and a rejected promise handed to\n * `showBoundary` carries whatever the library rejected with. `String(value)` is not safe on its\n * own either: it throws a TypeError of its own on a symbol, which would replace the application's\n * error with one from the boundary.\n */\nfunction describe(value: unknown): string {\n  if (typeof value === \"string\") return value\n  try {\n    return `A value that is not an Error was thrown: ${String(value)}`\n  } catch {\n    return \"A value that is not an Error was thrown\"\n  }\n}\n\n/**\n * The thrown value as an Error, without discarding what was actually thrown.\n *\n * Two cases need the conversion. A non-Error value has no `message` for a fallback to show, and a\n * fallback written against `error.message` would render \"undefined\" rather than fail — the worse\n * of the two outcomes. And an Error from another realm — an iframe, a worker, a `vm` context in a\n * test — fails `instanceof Error` while being an error in every way that matters, so it is matched\n * on having a string `message` instead of being thrown away as \"not an Error\".\n *\n * The original is kept on `cause` either way, because a logger wants the object the application\n * threw and not this wrapper.\n */\nfunction toError(value: unknown): Error {\n  if (value instanceof Error) return value\n  const errorLike =\n    typeof value === \"object\" &&\n    value !== null &&\n    typeof (value as { message?: unknown }).message === \"string\"\n  const error = new Error(errorLike ? (value as { message: string }).message : describe(value))\n  // Not `new Error(message, { cause })`: that overload needs the ES2022 lib, and this file has to\n  // typecheck inside whatever target the project installing it already has. Assigning the property\n  // afterwards is the same thing at runtime.\n  ;(error as Error & { cause?: unknown }).cause = value\n  return error\n}\n\n/** What the nearest boundary exposes to everything below it. */\nexport interface ErrorBoundaryContextValue {\n  /** The error it is currently showing a fallback for, or null while the children are rendering. */\n  error: Error | null\n  /** Clears the error and renders the children again. */\n  reset: () => void\n}\n\nexport const ErrorBoundaryContext = React.createContext<ErrorBoundaryContextValue | null>(null)\n\n/** What a fallback is handed: the error it stands in for, and the way back. */\nexport interface ErrorBoundaryFallbackProps {\n  /** The error, normalised — a non-Error throw arrives wrapped, with the original on `cause`. */\n  error: Error\n  /** Clears the error and renders the children again. Fires `onReset` with reason \"manual\". */\n  reset: () => void\n  /**\n   * Whether the crash unmounted something that had already been on screen.\n   *\n   * False when the children threw on their first render — nothing the user was looking at went\n   * away, so nothing about their position was lost. True otherwise, which is the case where a\n   * focused element has just been removed from the document and the browser has dropped focus to\n   * the body; see `ErrorFallback`, which uses this to decide whether to take focus.\n   */\n  recoverFocus: boolean\n}\n\n/** Why the boundary cleared its error. */\nexport type ErrorBoundaryResetReason = \"manual\" | \"keys\"\n\nexport interface ErrorBoundaryProps {\n  children?: React.ReactNode\n  /**\n   * What to render instead of the children.\n   *\n   * A node, or a function given {@link ErrorBoundaryFallbackProps}. Omit it for the built-in\n   * {@link ErrorFallback}; pass `null` to render nothing, which is what a decorative widget in a\n   * dashboard usually wants.\n   *\n   * Whatever it renders is outside this boundary's reach: React does not let a boundary catch an\n   * error thrown by its own render, so a fallback that throws goes to the boundary above this one,\n   * and if there is none the page is blank after all. Keep it to markup.\n   */\n  fallback?: React.ReactNode | ((props: ErrorBoundaryFallbackProps) => React.ReactNode)\n  /**\n   * Values that clear the error when they change — a route, a record id, a retry counter.\n   *\n   * Compared element by element, so the ordinary `resetKeys={[pathname]}` does not count as a\n   * change on every render of the parent. Changing them does not re-run anything by itself: it\n   * renders the children again, which throw again unless whatever made them throw is also gone.\n   */\n  resetKeys?: readonly unknown[]\n  /**\n   * Called once per error, in the commit that shows the fallback — the place to report it.\n   *\n   * `componentStack` is React's own list of the components above the throw, and it is null when\n   * the error came in through {@link useErrorBoundary} rather than out of a render. Both it and\n   * `error.message` routinely carry the thing being rendered — an email address, an order, an id —\n   * so treat the pair as user data when the destination is somebody else's service.\n   */\n  onError?: (error: Error, info: { componentStack: string | null }) => void\n  /** Called after the error is cleared, with the error that was showing and what cleared it. */\n  onReset?: (details: { reason: ErrorBoundaryResetReason; error: Error }) => void\n}\n\ninterface ErrorBoundaryState {\n  error: Error | null\n  /** The `resetKeys` the last render was given, so a change can be noticed without prevProps. */\n  keys: readonly unknown[]\n}\n\n/**\n * Catches a render error from anywhere below it and shows a fallback in place of that subtree,\n * instead of letting React unmount the whole application — one dashboard widget, a third-party\n * embed, a route, a row of a list.\n *\n * It is a class because React gives no other way: `getDerivedStateFromError` and\n * `componentDidCatch` have no hook equivalent, so this is the one component in a modern codebase\n * that cannot be a function. Writing it yourself is a dozen lines; the dozen lines are not the\n * reason to install one. These are:\n *\n * - **Clearing the error is not recovering.** Rendering the fallback unmounts the children, so a\n *   reset does mount them fresh and their state is genuinely gone — but the reason they threw is\n *   usually in the props or in a store, and that has not moved. `onReset` is where the caller\n *   drops the bad response, bumps the query key, or navigates; `resetKeys` is where it says what\n *   counts as the cause having changed.\n * - **A reset loop is easy to write by accident.** Keys are compared element by element and\n *   snapshotted as they are seen, so passing a fresh array literal does not reset anything, and a\n *   child that throws again under the same keys stops rather than cycling.\n * - **Half the errors in an application never reach a boundary.** An event handler, a `setTimeout`,\n *   a rejected promise and the server render are all outside the render path React watches.\n *   {@link useErrorBoundary} is the way to hand those in deliberately.\n * - **Focus is lost when the subtree goes.** The element that had it is no longer in the document,\n *   so the browser puts focus on the body and a keyboard user is silently returned to the top of\n *   the page. The built-in fallback takes focus back, and only in that case.\n *\n * What it cannot do is catch errors thrown during its own render, which includes the fallback, and\n * it does nothing on the server: `componentDidCatch` is a commit-phase lifecycle and the server\n * never commits. It is also not a quiet one in development — React logs an error it recovers from\n * either way, which is why this component does not log one of its own.\n */\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n  /**\n   * Whether the children have ever been on screen. See `recoverFocus`: a child that throws on its\n   * first render took nothing away from the user, and a fallback should not pull focus for it.\n   */\n  private childrenCommitted = false\n\n  /**\n   * The raw value `onError` has already been called for, boxed so that a thrown `null` or\n   * `undefined` is still distinguishable from \"nothing reported yet\". Cleared on reset, so the\n   * same error thrown again after a retry is a second report rather than a silent one.\n   */\n  private reportedFor: { value: unknown } | null = null\n\n  /** Set by `reset()` so the `onReset` that follows can say it was a person and not the keys. */\n  private pendingReason: ErrorBoundaryResetReason | null = null\n\n  /**\n   * Handed to the context, and replaced only when the error changes.\n   *\n   * A fresh object every render would re-render every consumer below on every render of this one,\n   * which for the healthy path is every render of the subtree the boundary is wrapping.\n   */\n  private contextValue: ErrorBoundaryContextValue\n\n  constructor(props: ErrorBoundaryProps) {\n    super(props)\n    this.state = { error: null, keys: props.resetKeys ?? NO_KEYS }\n    this.contextValue = { error: null, reset: this.reset }\n  }\n\n  static getDerivedStateFromError(value: unknown): Partial<ErrorBoundaryState> {\n    return { error: toError(value) }\n  }\n\n  /**\n   * Notices a `resetKeys` change — and, just as importantly, does not notice the one that was\n   * already in place when the children threw.\n   *\n   * This runs before every render, including the re-render that `getDerivedStateFromError` causes,\n   * which is what makes the snapshot right. A parent that re-renders with new keys *and* throws in\n   * the same pass updates the snapshot on the way in, so by the time the error lands the keys on\n   * record are the ones that were current when it was thrown. Comparing against `prevProps` in\n   * `componentDidUpdate` instead would read that same pass as \"the keys changed while an error was\n   * showing\", clear the error, and arrive back here one render later with the same throw.\n   */\n  static getDerivedStateFromProps(\n    props: ErrorBoundaryProps,\n    state: ErrorBoundaryState\n  ): Partial<ErrorBoundaryState> | null {\n    const keys = props.resetKeys ?? NO_KEYS\n    if (sameKeys(keys, state.keys)) return null\n    if (state.error === null) return { keys }\n    return { error: null, keys }\n  }\n\n  componentDidMount(): void {\n    if (this.state.error === null) this.childrenCommitted = true\n  }\n\n  componentDidCatch(error: Error, info: React.ErrorInfo): void {\n    // React hands over the value as it was thrown; `state.error` is the normalised one the fallback\n    // is about to be given, and the two are the same object whenever an actual Error was thrown.\n    if (this.reportedFor !== null && Object.is(this.reportedFor.value, error)) return\n    this.reportedFor = { value: error }\n    this.props.onError?.(this.state.error ?? toError(error), {\n      componentStack: info.componentStack ?? null,\n    })\n  }\n\n  componentDidUpdate(_prevProps: ErrorBoundaryProps, prevState: ErrorBoundaryState): void {\n    if (this.state.error !== null) return\n    this.childrenCommitted = true\n    if (prevState.error === null) return\n    this.reportedFor = null\n    const reason = this.pendingReason ?? \"keys\"\n    this.pendingReason = null\n    this.props.onReset?.({ reason, error: prevState.error })\n  }\n\n  /**\n   * Bound as a field rather than in the constructor so the identity is stable: it goes into the\n   * context value and into the fallback's props, and a new function each render would make both\n   * look like they had changed.\n   */\n  reset = (): void => {\n    if (this.state.error === null) return\n    this.pendingReason = \"manual\"\n    this.setState({ error: null, keys: this.props.resetKeys ?? NO_KEYS })\n  }\n\n  render(): React.ReactNode {\n    const { children, fallback } = this.props\n    const { error } = this.state\n\n    if (this.contextValue.error !== error) {\n      this.contextValue = { error, reset: this.reset }\n    }\n\n    let content: React.ReactNode\n    if (error === null) {\n      content = children\n    } else {\n      const props: ErrorBoundaryFallbackProps = {\n        error,\n        reset: this.reset,\n        recoverFocus: this.childrenCommitted,\n      }\n      if (typeof fallback === \"function\") content = fallback(props)\n      else if (fallback === undefined) content = <ErrorFallback {...props} />\n      else content = fallback\n    }\n\n    return (\n      <ErrorBoundaryContext.Provider value={this.contextValue}>\n        {content}\n      </ErrorBoundaryContext.Provider>\n    )\n  }\n}\n\nexport interface ErrorFallbackProps\n  extends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\" | \"title\">,\n    ErrorBoundaryFallbackProps {\n  /** The headline. Keep it about the part of the page that is missing, not about the exception. */\n  title?: string\n  /** The retry button's label. Pass null for a fallback with no way back. */\n  resetLabel?: string | null\n  /**\n   * Whether to render `error.message`.\n   *\n   * Off, because the message is written for whoever is reading the logs: it names internals, and\n   * on a server-rendered page it can name another request's data. React already prints the error\n   * and its component stack to the console in development, so turning this on is for the rare\n   * build where the console is not reachable.\n   */\n  showMessage?: boolean\n}\n\n/**\n * The fallback used when `ErrorBoundary` is given none: a bordered notice with a retry button.\n *\n * Exported so a custom fallback can keep the same shape —\n * `fallback={(p) => <ErrorFallback {...p} title=\"Chart unavailable\" />}`.\n */\nexport function ErrorFallback({\n  error,\n  reset,\n  recoverFocus,\n  title = \"Something went wrong\",\n  resetLabel = \"Try again\",\n  showMessage = false,\n  className,\n  ...props\n}: ErrorFallbackProps) {\n  const ref = React.useRef<HTMLDivElement | null>(null)\n\n  React.useEffect(() => {\n    if (!recoverFocus) return\n    const node = ref.current\n    if (!node) return\n    const doc = node.ownerDocument\n    const active = doc.activeElement\n    // Only when the browser has nowhere to put focus. If focus is still on something real it is\n    // somewhere else on the page and belongs to whoever is using it; it is when the focused element\n    // went down with the subtree that the browser falls back to the body, and a keyboard user is\n    // then at the top of the document with no sign that anything happened.\n    if (active && active !== doc.body) return\n    node.focus()\n  }, [recoverFocus])\n\n  return (\n    <div\n      ref={ref}\n      // Announced on arrival because it arrives — a live region that is inserted already populated\n      // is read, which is exactly this case. Focusable only programmatically, so recovering focus\n      // does not also add a tab stop to the page.\n      role=\"alert\"\n      tabIndex={-1}\n      className={cn(\n        \"flex flex-col items-start gap-3 rounded-lg border border-destructive/40 bg-card p-6 text-card-foreground\",\n        \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"flex items-center gap-2 text-destructive\">\n        <svg\n          aria-hidden=\"true\"\n          viewBox=\"0 0 24 24\"\n          fill=\"none\"\n          stroke=\"currentColor\"\n          strokeWidth=\"2\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          className=\"size-4 shrink-0\"\n        >\n          <path d=\"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z\" />\n          <path d=\"M12 9v4\" />\n          <path d=\"M12 17h.01\" />\n        </svg>\n        <p className=\"text-sm font-medium\">{title}</p>\n      </div>\n      {showMessage && error.message ? (\n        <p className=\"text-sm break-words text-muted-foreground\">{error.message}</p>\n      ) : null}\n      {resetLabel === null ? null : (\n        <button\n          type=\"button\"\n          onClick={reset}\n          className=\"inline-flex h-9 items-center justify-center rounded-md border border-input bg-transparent px-3 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n        >\n          {resetLabel}\n        </button>\n      )}\n    </div>\n  )\n}\n\nexport interface UseErrorBoundary<TError> {\n  /**\n   * Hands an error to the nearest boundary from somewhere React is not watching — a click handler,\n   * a timer, a rejected promise, a subscription callback.\n   */\n  showBoundary: (error: TError) => void\n  /** Clears the nearest boundary, if there is one. A no-op outside any boundary. */\n  resetBoundary: () => void\n}\n\n/**\n * The way to get an error that happened outside rendering to the boundary above you.\n *\n * This is the gap that makes people think their boundary is broken. React catches what is thrown\n * while it renders, and nothing else: `onClick={() => { throw e }}`, a `.catch` that rethrows, a\n * `setTimeout`, an `await` after the component has already returned — none of them are a render,\n * so the boundary never hears about them and the user is left looking at a page that quietly did\n * nothing. Calling `showBoundary(error)` stores it and rethrows it from this component's next\n * render, which is a render, so the boundary catches it with a real component stack and `onError`\n * reports it like any other.\n *\n * ```tsx\n * const { showBoundary } = useErrorBoundary()\n * React.useEffect(() => {\n *   load().then(setData, showBoundary)\n * }, [showBoundary])\n * ```\n *\n * No state has to be cleared afterwards: the boundary replaces this component with the fallback,\n * so the component holding the error unmounts, and a reset mounts a fresh one.\n */\nexport function useErrorBoundary<TError = unknown>(): UseErrorBoundary<TError> {\n  const context = React.useContext(ErrorBoundaryContext)\n  const [thrown, setThrown] = React.useState<{ value: TError } | null>(null)\n  const reset = context?.reset\n\n  const handle = React.useMemo(\n    () => ({\n      showBoundary: (error: TError) => setThrown({ value: error }),\n      resetBoundary: () => {\n        setThrown(null)\n        reset?.()\n      },\n    }),\n    [reset]\n  )\n\n  // After the hooks, never between them: a throw placed above `useMemo` would leave this render\n  // having called two hooks where the last one called three, and a component that leaves a render\n  // half-done is a worse thing to ship than the error it is reporting.\n  //\n  // Boxed rather than stored bare, so that `showBoundary(null)` — which a rejected promise can\n  // genuinely produce — is still a throw and not a component that looks fine forever.\n  if (thrown !== null) throw thrown.value\n  return handle\n}\n\n/**\n * Wraps a component in a boundary — the ordinary way to protect a route or a page-level component\n * whose own file is the only place you can reach.\n */\nexport function withErrorBoundary<P extends object>(\n  Component: React.ComponentType<P>,\n  boundaryProps?: Omit<ErrorBoundaryProps, \"children\">\n): React.ComponentType<P> {\n  function Wrapped(props: P) {\n    return (\n      <ErrorBoundary {...boundaryProps}>\n        <Component {...props} />\n      </ErrorBoundary>\n    )\n  }\n  Wrapped.displayName = `withErrorBoundary(${Component.displayName || Component.name || \"Component\"})`\n  return Wrapped\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui",
  "docs": "Install any pulld component by name: add \"@pulld\": \"https://pulld.pages.dev/r/{name}.json\" to the registries block in components.json, then `npx shadcn add @pulld/<name>`. All 140 components: https://pulld.pages.dev/?utm_source=cli"
}
