@fanvue/ui publishes five JavaScript entry points and one styles subpath. Most code imports from the root; the other four exist so that a feature nobody uses costs nothing, either in bundle bytes or in a peer dependency you have to install.
The entry points
Each JavaScript entry point resolves to both an ESM and a CommonJS build with the same type declarations, so
import and require behave identically.
Nothing is duplicated across entry points
Chart*, DatePicker, and CountryFlag are exported only from their own subpath, never from the root. If an import of DatePicker from @fanvue/ui fails to resolve, the fix is the import path, not the version.Why the split
Three reasons, and each subpath exists for at least one of them. Optional peer dependencies.recharts, react-day-picker, and motion are declared optional in peerDependenciesMeta. Keeping the code that imports them off the root means installing @fanvue/ui never pulls them in and never warns about them. A root export would make every consumer either install all three or live with unresolved imports.
Payload. The flag artwork is a generated table of SVG shapes for 265 country codes, around 167 KB of source before minification, which is larger than a typical app’s entire component payload. It stays behind its own import so only apps that render flags pay for it.
Size budgets in CI. Two entry points are size-checked on every pull request with size-limit: dist/index.mjs has a 220 KB budget and dist/animated-icons.mjs has a 15 KB budget. Each is measured with its heavy dependencies excluded from the count: Radix, clsx, tailwind-merge, react-day-picker, and recharts for the root, and clsx, tailwind-merge, and motion for the animated icons. A change that pushes either past its budget fails the build.
Tree-shaking backs all of this up. The library uses explicit named exports only, never export *, and declares sideEffects as CSS files alone, so a modern bundler drops everything you did not import.
@fanvue/ui
The default import for almost everything.
Slot and Slottable
Slot and Slottable are re-exported from @radix-ui/react-slot at the root, so composition helpers come from one package rather than two, and your app and the library share a single copy of the primitive.
asChild merge their props and class names onto the child element instead of rendering their own. That is how a button becomes a link without losing its styling:
Slot is exported for the same pattern in your own components. See Button for the props it accepts.
@fanvue/ui/charts
Composable chart parts that theme Recharts with Fanvue’s tokens. You render the Recharts chart yourself and wrap it in ChartContainer, which provides responsive sizing and the series configuration that tooltips and legends read.
Revenue.tsx
ChartConfig entry takes either a single color or a theme map with light and dark keys, which is how a series can use a different colour per theme:
ChartCard, ChartLegend, ChartLegendContent, ChartPieLegend, ChartCenterLabel, ChartMetricTrend, ChartSeriesToggle, ChartSkeleton, ChartLoadingOverlay, ChartStyle, and the useChart hook.
@fanvue/ui/date-picker
DatePicker wraps react-day-picker and accepts its props, so single dates, ranges, and multiple selection all work through the underlying API.
@fanvue/ui/flags
CountryFlag renders a circular flag from a country code, drawn as inline SVG with no network request.
country prop is a case-insensitive string, size is one of 16 | 20 | 24 | 32 and defaults to 20, and label sets the accessible name. Leave label unset when the country’s name is already next to the flag: the SVG is then hidden from assistive technology rather than read out twice.
Codes are mostly ISO 3166-1 alpha-2, plus the extras the artwork source ships (eu, un, xk, and others), 265 in all. CountryFlagCode is the exhaustive union of the codes artwork exists for, and it is exported so you can narrow your own data against it. It is deliberately not the type of the country prop: a code with no artwork renders the source’s grey xx placeholder disc instead, so a live feed of country codes can be passed straight through without a runtime guard.
The full set is on the CountryFlag page.
@fanvue/ui/animated-icons
Animated twins of the static icons. Every export here matches a static icon of the same name and renders in exactly the same box, so switching is a one-line import change and nothing in your layout moves.
- Not every icon has a twin. 69 of the static icons are mapped. A missing export means no equivalent was accepted, not a bug.
SpinnerIconis deliberately absent, because a loading indicator must not wait for a hover; use the static one withanimate-spin, orLoader. - Reduced motion is respected. Nothing animates under
prefers-reduced-motion: reduce, including animations you start yourself throughcontrolRef. - Drive the animation from a parent for icons inside buttons. Passing
controlRefturns the built-in hover trigger off and hands youstartAnimationandstopAnimation. Wire focus as well as hover: the<svg>is not focusable, so a keyboard user reaching the button gets nothing from hover alone. - The artwork is stroke-only. These icons take no
filledprop, and passing one is a type error rather than a silent no-op.
@fanvue/ui/styles/*
A wildcard subpath serving the token stylesheets from dist/styles/. Apps import one file:
app.css
theme.css imports base.css itself, so importing base.css separately is unnecessary. Both are Tailwind v4 source files rather than compiled CSS. See Tailwind setup for the full entry point and Theming for what the tokens contain.
Next steps
Installation
Optional peer dependencies and which feature each one unlocks.
Theming
The tokens charts and components both read from.