---
title: "Upstream bugs in component libraries, grouped by pattern (components)"
description: "These 48 bugs were found by reading registry source (fetched 2026-09-16) and in shipped apps."
canonical: https://void-design.vercel.app/docs/components/upstream-bugs
lastModified: 2026-09-16
---

# Upstream bugs in component libraries, grouped by pattern

These 48 bugs were found by reading registry source (fetched 2026-09-16) and in shipped apps. They are grouped by **pattern**: when you audit any registry component, scan for each pattern's signature, not just for the named components. Lint ids are `void lint` rules that catch the pattern statically.

Format: **Library / component**: the bug → the impact. The fix pattern closes each group.

## 1. Dead on Tailwind v4 (silent: no error, the effect never shows)

Signature: `animate-<custom>` classes with no `css`/`cssVars` in the registry item; keyframes in `tailwind.config.*` or in comments; v3 utility names; undefined theme classes.

- **Aceternity `spotlight`**: `animate-spotlight` ships with no CSS, and the base class is `opacity-0` → invisible forever.
- **Aceternity `meteors`, `moving-border`** (and other custom `animate-*` items): no CSS in the registry item → no animation.
- **React Bits `StarBorder`**: keyframes exist only as a commented `tailwind.config.js` block → static.
- **Registries generally**: `bg-gradient-to-*`, `flex-shrink-0`, bare `shadow`/`rounded`, `outline-none`, config keyframes → gradients missing, sizes one step off.
- **Cult `direction-aware-tabs`**: undefined `shadow-inner-shadow` → silent style loss.
- **kibo `gantt`**: undefined `--color-backdrop` → silent style loss.
- **ReUI `frame`**: served JSON lost variant prefixes → dead variants.

**Fix pattern:** put `@keyframes` + a class in `@layer components`, or `--animate-x` + `@keyframes` in `@theme`. Rename v3 utilities (`bg-linear-to-*`, `shrink-0`, `shadow-xs`, `outline-hidden`). Run `next build` and confirm the class exists in the compiled CSS. Lint: `lint/tw-unknown-class`, `lint/tw-js-config-ignored`, `lint/tw-v3-renamed`, `lint/tw-v3-arbitrary-var`.

## 2. Hidden or placeholder server HTML (SEO, no-JS, LCP)

Signature: `opacity-0`, `initial={{ opacity: 0 }}` or `initial="hidden"` on text; a number component rendering `0`/`""`/`startValue`; GSAP `set` after hydration.

- **Magic UI `number-ticker`**: SSR renders `startValue` (`0`), and a width change from `0` to `12,400` causes CLS → crawlers and link previews see 0.
- **React Bits `CountUp`**: SSR renders an empty `<span />` → no number without JS.
- **Aceternity `text-generate-effect`**: every word SSRs at `opacity-0` + `blur(10px)` → invisible without JS; LCP delayed to the end of a 0.2s × N stagger.
- **Magic UI `text-animate`**: `initial="hidden"` → text at opacity 0 before hydration.
- **React Bits `SplitText`**: full text on the server, then GSAP sets `opacity:0; y:40` after `fonts.ready` → flash, hide, reveal; LCP moves.
- **React Bits `SplitText`**: `willChange: "transform, opacity"` left on the parent after completion; pulls gsap + ScrollTrigger + SplitText (~45–70 KB) for one headline → a permanent layer; weight. Lint: `lint/will-change-static`.

**Fix pattern:** SSR the final value and visible text. Animate position, not visibility, on LCP text (`RevealText`). Numbers animate only if they start offscreen (`NumberTicker`, or `@number-flow/react`).

## 3. SSR crashes and hydration mismatches

Signature: `window`/`document`/`navigator`/`matchMedia`/`localStorage` at module scope or in render; `Math.random()`/`Date.now()` in render; `createPortal(document.body)` in render.

- **Skiper106**: `navigator.userAgent` at module scope → SSR crash.
- **Aceternity `background-beams`**: `Math.random()` in render for duration, delay and `y2` → hydration mismatch, and values re-randomise each render.
- **Aceternity (26 of 118 free items)**: `Math.random()` in render → hydration risk.
- **Magic UI `globe`**: `setTimeout(() => style.opacity = "1", 0)` → a hydration-timing hack.
- **React Bits (all 171 files)**: no `'use client'` → RSC import errors.

**Fix pattern:** browser globals only inside effects or `useSyncExternalStore` (server snapshot). Seeded or precomputed values instead of `Math.random()` in render. `'use client'` only on the interactive leaf. Lint: `lint/browser-global-in-render`.

## 4. Leaks: subscriptions and loops without cleanup

Signature: `.on('change'` or `addEventListener` outside `useEffect`; `requestAnimationFrame` without `cancelAnimationFrame`; `new Lenis` without `destroy`; `api.on` without `off`; `setInterval` per instance.

- **Skiper34, Skiper37**: `scrollY.on('change')` in the render body → a new listener every render.
- **Skiper30** (+16/17/28/31/34): the Lenis rAF loop is never cancelled and `lenis.destroy()` is missing → a permanent rAF after unmount.
- **Skiper54**: `api.on('select')` is never removed → listener leak.
- **kibo `relative-time`**: a `setInterval` per instance, never paused → N timers.

**Fix pattern:** `useMotionValueEvent` or an effect with an unsubscribe. Match every add, observe, rAF, interval or create with its remove, disconnect, cancel, clear or destroy. One shared ticker for lists. No Lenis. Lint: `lint/motionvalue-subscribe-in-render`, `lint/raf-without-cancel`, `lint/listener-without-cleanup`, `lint/timer-in-render`.

## 5. Hooks misuse

Signature: `use[A-Z]…(` inside `&&`, ternaries, JSX or `style={{}}`; `m.create()` or component definitions in render; `ref.current` in deps; props already read from refs listed in effect deps.

- **Magic UI `magic-card`**: `useMotionTemplate` inside `{mode === "gradient" && …}` → React throws when `mode` changes.
- **Skiper19**: `useTransform` inside a `style={{}}` literal → rules-of-hooks violation.
- **tailark `animated-group`**: `m.create()` in render → remount and replay every render.
- **Aceternity `text-generate-effect`**: `[scope.current]` as an effect dep → a stale or ineffective effect.
- **React Bits `Aurora`**: deps `[amplitude]` although the value is read from a ref → destroys and rebuilds the WebGL context on prop change.
- **Magic UI `globe`**: `config` object in effect deps → inline `config={{…}}` recreates the globe every render.
- **Cult `direction-aware-tabs`**: hardcoded `layoutId="bubble"` → two instances fight.

**Fix pattern:** hooks at the top level; `useMemo` for created components; `useId()`-scoped `layoutId`; stable primitives in deps; update uniforms instead of rebuilding.

## 6. Per-frame React work and allocation

Signature: `setState` inside `mousemove`/`pointermove`/`scroll`/rAF/`useAnimationFrame`; `new Intl.NumberFormat`, `new Color` or `getBoundingClientRect` inside loops; `window` listeners per instance.

- **React Bits `Magnet`**: a window `mousemove` per instance + `getBoundingClientRect` + `setState` on every move → N listeners, layout reads and re-renders per event.
- **React Bits `SpotlightCard`**: `setState` per move and a repainted full-card `radial-gradient` → re-renders children every frame.
- **Magic UI `number-ticker`, React Bits `CountUp`**: a new `Intl.NumberFormat` per frame, locale hardcoded to `en-US` → GC churn; wrong locale.
- **React Bits `Aurora`**: `new Color()` ×3 per frame → ~420 allocations/s.
- **Aceternity `dotted-glow-background`**: `getBoundingClientRect` inside draw + `shadowBlur` per dot → forced layout at 60fps.
- **ReUI `scrollspy`**: capture-phase scroll + a forced layout loop; its `throttleTime` prop is unused → scroll jank.
- **Magic UI `number-ticker`**: `useSpring` with damping 60 → slow settle (the top idle cost in a shipped app).

**Fix pattern:** refs + one rAF writing `el.style.translate` (`SpotlightCard`, `Magnetic`); measure once on enter or in a ResizeObserver; hoist formatters; IntersectionObserver instead of scroll listeners; near-critical springs.

## 7. Never stops: offscreen spin and no visibility pause

Signature: `repeat: Infinity`, `infinite`, `useAnimationFrame` or a rAF loop with no IntersectionObserver, `useInView` or `data-fx`; WebGL libraries' internal loops.

- **Magic UI `border-beam`**: motion animates `offset-distance` on the main thread forever → idle CPU.
- **motion-primitives `border-trail`, tailark `infinite-slider`**: `repeat: Infinity`, never paused → idle main thread.
- **React Bits `ShinyText`**: a perpetual `useAnimationFrame` writing `background-position` (still ticking when `disabled`) → a paint every frame per instance.
- **Magic UI `globe`**: cobe's rAF runs until unmount; no IntersectionObserver or visibility pause → GPU burn.
- **Magic UI `animated-beam`**: `repeat = Infinity` JS gradient animation → a repaint every frame.
- **Magic UI `animated-beam`**: its ResizeObserver watches only the container; endpoints that move (font swap, image load, accordion) leave the beam pointing at stale coordinates.
- **React Bits backgrounds**: 35/56 have no offscreen pause, 53/56 no reduced motion, 23/56 no DPR cap → GPU burn; WCAG 2.3.3.
- **Aceternity `spotlight-new`**: infinite motion + `z-40` → covers content and never rests.

**Fix pattern:** CSS animation + `data-fx` + `FxGate` (recipes §0). JS loops cancel (not skip) on IntersectionObserver and `visibilitychange`. Lint: `smooth/raf-loop-idle`.

## 8. Paint-bound or layout-bound animation

Signature: animating `background`, `background-position`, `filter`, `box-shadow`, SVG gradient attributes, `width`/`height`/`top`/`left`; many stacked `backdrop-filter`s; `mask-image` over animated children.

- **RareUI `HookSidebar`**: springs `top`/`height` → layout every frame.
- **Magic UI `animated-beam`**: animates `x1/x2/y1/y2` of a `linearGradient` → path repaint per frame.
- **Aceternity `background-beams`**: 50 SVG paths × animated gradients, no IntersectionObserver or RM → CPU raster.
- **Magic UI `magic-card`** (orb mode): `filter: blur(60px)` on a 420px element moving with the pointer → a huge blurred layer per frame.
- **Aceternity `text-generate-effect`**: `filter: blur` animated per word → rasterisation per word per frame.
- **tailark `progressive-blur`**: 8 stacked `backdrop-filter` layers → 8–15ms per frame.
- **kibo `gantt`**: 5× `backdrop-blur` on sticky elements → scroll jank.
- **void measurement** (recipes §8–9): a `mask-image` fade over animated blobs → 10% dropped frames; a paint animation over an animated backdrop without its own layer → 14–46%.

**Fix pattern:** move pre-rasterised layers with `translate`/`rotate` (`BeamBorder`, `AuroraBackdrop`, `SpotlightCard`); one blur + one mask; a static overlay instead of a mask over animation; `will-change: transform` on a single small paint-animated element. Lint: `lint/animate-layout-prop`, `lint/transition-all`, `smooth/animate-layout-property`.

## 9. DOM and node explosions

Signature: `Array(n).fill().map` of animated nodes; per-character motion spans; SVG `<circle>` grids.

- **Magic UI `dot-pattern`** (glow): ~5,130 `<circle>`s, each with an infinite spring → DOM and animation explosion.
- **Magic UI `animated-grid-pattern`**: the same node explosion.
- **motion-primitives `text-effect`**: per-character motion nodes by default → ~60 nodes per headline.

**Fix pattern:** CSS gradients (`PatternBackdrop`); `per="word"` or CSS per-word (`RevealText`).

## 10. WebGL, canvas and expensive dependencies

Signature: a `getContext('webgl')`/`<Canvas>`/`createGlobe` per instance or in `.map()`; DPR 2 hardcoded; three/R3F for a 2D quad; heavy or stale dependencies.

- **RareUI `FluidOrb`**: one WebGL context per instance, uncapped rAF, DPR 2 → the 9th context evicts the 1st in lists.
- **React Bits `Silk`**: three + R3F (~150 KB) for one quad, `frameloop="always"` → the worst cost/benefit.
- **React Bits `GridScan`**: imports `face-api.js` (~700 KB + weights) → a bundle bomb.
- **Aceternity `globe`/`3d-globe`/`canvas-reveal-effect`/`vortex`**: three-globe or R3F, one context each → 600 KB+.
- **Magic UI `globe`**: pins `cobe@^0.6.4` (current 2.0.1); `devicePixelRatio: 2` and `width * 2` hardcoded; `mapSamples: 16000` → a stale major; 4× pixels on DPR-1 screens.
- **Magic UI `globe`**: drag uses `onPointerOut` with no `setPointerCapture` → the drag drops at the canvas edge.
- **Animate UI** (17 items): depends on `@base-ui-components/react` (renamed to `@base-ui/react`) → a duplicate, older Base UI.
- **shadcnblocks**: `import { cn } from "cn"` + a `"cn"` dependency → phantom dependency.
- **ReUI `tree`/`rating`**: site-internal `@/app/(create)/…` imports → build break.

**Fix pattern:** ≤1 context per page, never in lists (static seeded frame for many instances); DPR ≤1.5; ≤30fps; ogl or raw WebGL2 per `speed` → `references/rendering-smoothness.md` §8; cobe 2.x for globes; diff registry `dependencies` against `package.json`. Lint: `lint/webgl-in-map`, `lint/heavy-import`, `smooth/multiple-webgl-contexts`.

## 11. Accessibility

Signature: duplicated content without `aria-hidden`/`inert`; `aria-label` on generic elements; clickable `<li>`/`<div>`; `<button>` without `type`; hover-only behaviour; decorative SVG without `aria-hidden`; global SVG ids.

- **Magic UI `marquee`**: 3 duplicate copies without `aria-hidden`/`inert`; hover-only pause → links read and tabbed 4×; WCAG 2.2.2.
- **Skiper58 `TextRoll`**: two copies of every letter with no `aria-hidden` → "H o m e H o m e".
- **Skiper58 `TextRoll`**: nav items with `href` data render `<li className="cursor-pointer">` with no `<a>` → not focusable, not crawlable.
- **Skiper58 `TextRoll`**: hover-only, `ease: "easeInOut"` on enter, `key={index}`, `framer-motion` import → no focus parity.
- **Magic UI `text-animate`**: `aria-label` on a generic div/p + `sr-only` duplicate + `aria-hidden` segments → double announcement; label ignored.
- **React Bits `StarBorder`**: `as` defaults to `'button'` with no `type` → submits enclosing forms.
- **Magic UI `animated-beam`**: decorative SVG without `aria-hidden` → noise for screen readers.
- **Aceternity `spotlight`**: hardcoded `id="filter"` + a 151px `feGaussianBlur` + `z-[1]` over content → cross-instance filter collisions; expensive raster.
- **kibo `tree`**: zero ARIA while the docs claim keyboard support → inaccessible.
- **RareUI `HookSidebar`**: exact `href === pathname` → nested routes highlight nothing.
- **Skiper101**: exports its demo as `Skiper102` → name collision.

**Fix pattern:** duplicates get `aria-hidden="true" inert`; decorative layers get `aria-hidden`; real `<a href>`/`<button type="button">`; `:focus-visible`/`:focus-within` parity; a pause control for >5s motion; `useId()` for SVG ids; `@headless-tree/react` for trees; longest-prefix route matching. Lint: `lint/div-button`.

## 12. Off-token styling (every library)

Signature: hex/rgb/hsl literals, `neutral-*`/`zinc-*`/`purple-*` classes, `dark:text-white text-black`, purple→pink gradient pairs, `next-themes` just to pick a blend mode.

- **Magic UI `border-beam`**: `#ffaa40 → #9c40ff` → off-brand; `design/purple-gradient`.
- **Magic UI `magic-card`**: `#9E7AFF → #FE8BBB`, `#ee4f27 → #6b21ef`; `next-themes` dependency → second accent; extra dependency.
- **Aceternity `background-beams`**: `#18CCFC → #6344F5 → #AE48FF` → the purple→pink trope.
- **React Bits `SpotlightCard`, `StarBorder`**: `neutral-800/900`, `#000/#fff/#222` → breaks light mode and directions.
- **RareUI**: orange defaults → off-brand.

**Fix pattern:** the token mapping table in SKILL.md; one hue via `--brand` + `color-mix(in oklab, …)`. Lint: `lint/hardcoded-colors`, `design/multiple-accents`, `design/gradient-text`.

---

Sources: registry JSON under `magicui.design/r`, `reactbits.dev/r`, `ui.aceternity.com/registry`, `skiper-ui.com/registry`, `coss.com/ui/r`, `animate-ui.com/r`; repos listed in `catalogue.md`; owner research `~/code/sandbox/void/ui/v3/component-libs.md` §3 and `local-digest.md` §4.
