Common issues and solutions when using @neynar/ui.
Error: Cannot find module '@neynar/ui/button'
Solutions:
-
Ensure the package is installed:
npm install @neynar/ui
-
Clear node_modules and reinstall:
rm -rf node_modules package-lock.json npm install
-
For monorepos, ensure the workspace is linked correctly.
Error: WARN peer dependency react@^19 not installed
Solution: @neynar/ui requires React 19+. Upgrade React:
npm install react@^19 react-dom@^19Symptom: Components render but have no styling.
Solutions:
-
Import base and theme in your CSS entry point:
/* app/globals.css or src/index.css */ @import "@neynar/ui/styles"; @import "@neynar/ui/themes/purple-dawn"; /* Or first-light */
-
Ensure Tailwind is configured to scan node_modules:
// tailwind.config.ts content: [ "./src/**/*.{js,ts,jsx,tsx}", "./node_modules/@neynar/ui/dist/**/*.js", ]
-
Verify CSS is being processed by your bundler.
Symptom: Theme toggle doesn't change colors.
Solutions:
-
Add the ColorModeInitializer component to your layout:
import { ColorModeInitializer } from "@neynar/ui/color-mode"; // In your root layout <html> <head> <ColorModeInitializer /> </head> </html>
-
Ensure
suppressHydrationWarningis on<html>:<html suppressHydrationWarning>
Symptom: Brief flash of wrong theme on page load.
Solutions:
-
Move ColorModeInitializer component to
<head>:<head> <ColorModeInitializer /> </head>
-
Ensure your globals.css imports are correct:
@import "@neynar/ui/styles"; @import "@neynar/ui/themes/purple-dawn";
Error: Property 'X' does not exist on type...
Solutions:
-
Ensure you're using the correct component variant:
// Button variants: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "success" | "warning" | "info" import { Button } from "@neynar/ui/button"; <Button variant="outline">Click</Button>
-
Check prop types in your IDE - hover over component for available props.
Issue: Can't infer generic types for components like Select.
Solution: Explicitly type your values:
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@neynar/ui/select";
const [value, setValue] = useState<string>("");
<Select value={value} onValueChange={(v) => v && setValue(v)}>
...
</Select>Error: Hydration failed because the initial UI does not match...
Solutions:
-
Add
suppressHydrationWarningto html element:<html lang="en" suppressHydrationWarning>
-
Ensure ColorModeInitializer component is in the head, not body.
-
For dynamic content, use client-side rendering:
const [mounted, setMounted] = useState(false); useEffect(() => setMounted(true), []); if (!mounted) return null;
Issue: ref prop not forwarding to DOM element.
Solution: Most @neynar/ui components forward refs. Check you're using the correct ref type:
import { Button } from "@neynar/ui/button";
const buttonRef = useRef<HTMLButtonElement>(null);
<Button ref={buttonRef}>Click</Button>Solutions:
-
Ensure you have both trigger and content:
import { Dialog, DialogTrigger, DialogContent } from "@neynar/ui/dialog"; import { Button } from "@neynar/ui/button"; <Dialog> <DialogTrigger> <Button>Open</Button> </DialogTrigger> <DialogContent> Content here </DialogContent> </Dialog>
-
For controlled usage, manage open state:
const [open, setOpen] = useState(false); <Dialog open={open} onOpenChange={setOpen}>
Solution: Handle null values in onValueChange:
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@neynar/ui/select";
<Select
value={value}
onValueChange={(v) => v && setValue(v)}
>Solution: Use proper handlers for different modes:
import { Calendar } from "@neynar/ui/calendar";
// Single date
<Calendar
mode="single"
selected={date}
onSelect={setDate}
/>
// Date range
<Calendar
mode="range"
selected={dateRange}
onSelect={(range) => range?.from && setDateRange({ from: range.from, to: range.to })}
/>Solutions:
-
Use per-component imports:
// Good - Only imports what's needed import { Button } from "@neynar/ui/button"; import { Card } from "@neynar/ui/card";
-
Use dynamic imports for heavy components:
import dynamic from "next/dynamic"; import { Chart } from "@neynar/ui/chart"; const ChartLazy = dynamic(() => import("@neynar/ui/chart").then(m => ({ default: m.Chart })), { ssr: false });
Solutions:
- Lazy load components not needed immediately.
- Use Suspense with loading states.
- Consider code splitting by route.
If you can't resolve an issue:
- Check Storybook for working examples
- Search existing GitHub issues
- Create a new issue with:
- @neynar/ui version
- Framework and version (Next.js, Vite, etc.)
- Minimal reproduction code
- Expected vs actual behavior