@fewchurs/react
A feature-request board for any React app: visitors submit ideas, vote, comment and follow, and you manage everything from your Fewchurs dashboard. This package has the components, hooks, styles and fetch client.
Using Next.js? Use @fewchurs/next instead. It renders
the board on the server and keeps your API key out of the browser.
- React 18 or 19, no runtime dependencies, no Tailwind or CSS-in-JS needed
- Light and dark mode out of the box
- Fully typed, with a headless mode and hooks if you want your own UI
Integrate in 4 steps
1. Get an API key and add your domain
In the Fewchurs dashboard, open your app, copy the API key (it looks like
fr_live_…) and add the domain your app runs on. The key only works on domains you have added.
2. Install
npm install @fewchurs/react
# or: pnpm add @fewchurs/react
# or: yarn add @fewchurs/react
3. Put the key in an environment variable
Vite:
# .env
VITE_FEWCHURS_KEY=fr_live_…
Create React App uses process.env.REACT_APP_FEWCHURS_KEY; any other bundler works the same way.
Restart the dev server after you edit .env.
4. Render the board
// src/App.tsx
import { FewchursBoard, FewchursProvider } from "@fewchurs/react";
import "@fewchurs/react/styles.css";
export function App() {
return (
<FewchursProvider apiKey={import.meta.env.VITE_FEWCHURS_KEY}>
<FewchursBoard />
</FewchursProvider>
);
}
That is the whole integration. Run your app and the board shows up with tabs, voting, comments and a New request form.
The key is publishable, like a Stripe or PostHog public key. It is protected by the domains you added and by server-side rate limiting, not by secrecy. If you would rather keep it off the page, point the provider at your own proxy instead:
<FewchursProvider baseUrl="/api/fewchurs">.
Show it as a button instead of a page
FewchursButton renders only a button. Clicking it slides the board in as a sheet (from the side on
desktop, from the bottom on a phone). Nothing is fetched until it opens.
<FewchursProvider apiKey={import.meta.env.VITE_FEWCHURS_KEY}>
<FewchursButton floating>Suggest a feature</FewchursButton>
</FewchursProvider>
| Prop | What it does |
|---|---|
floating | Pins the button to the bottom right of every page |
floating="left" | Pins it to the bottom left |
children | Your own label. The default is "Feedback" |
className, style | Go on the button |
any FewchursBoard prop | Goes to the board inside the sheet |
To open the sheet from your own button, use FewchursBoardDialog with open, onClose and
variant="sheet". Leave variant out for a centered modal.
Customize
Start with the defaults and go deeper only when you need to.
CSS variables (the quickest way to match your brand):
.fewchurs {
--fw-primary: #ed5f18;
--fw-radius: 12px;
--fw-font: var(--font-sans);
--fw-surface: #fff;
}
Props:
<FewchursBoard
tabs={["top", "new", "roadmap"]} // default: ["top", "new"]
defaultTab="top"
showDeclined={false}
allowComments
emailField="optional"
pageSize={20}
theme={{ primary: "#0f766e", radius: 4 }}
colorScheme="system" // "light" | "dark" | "system"
labels={{ title: "Ideas", submit: "Suggest an idea" }}
/>
Slots: renderHeader, renderEmpty and renderFeature replace parts of the board.
Headless: compose FewchursBoard.Root, .Tabs, .List and .SubmitTrigger yourself, add
unstyled to drop every class name, or skip the components and build on the hooks below.
Hooks
const { features, isLoading, error, loadMore, hasMore } = useFeatures({ sort: "top" });
const { hasVoted, upvoteCount, toggle, isPending } = useVote(featureId);
const { comments, add, loadMore } = useComments(featureId);
const { submit, isPending } = useSubmitFeature();
const { isFollowing, follow, unfollow } = useFollow(featureId);
const { feature, isLoading, refresh } = useFeature(featureId);
const { showBranding, hideVoteCounts } = useFewchursConfig();
Hooks must be rendered inside FewchursProvider. They never throw: every failure is a typed value
with a code (invalid_key, validation_failed, rate_limited, not_found, limit_reached,
server, network), and userMessage(error) turns it into a sentence you can show.
Link straight to one request
<FewchursBoard
initialFeatureId={new URLSearchParams(location.search).get("request") ?? undefined}
/>
The request shows above the list with its comments open. An id that no longer exists is ignored.
Signed-in users
Votes are anonymous and tied to a device id that is generated on first use. To make votes follow the account across devices, pass a hashed user id. Never pass a raw id or an email address.
<FewchursProvider apiKey={key} deviceId={hashedUserId}>
Analytics
<FewchursProvider apiKey={key} onEvent={(event) => track(event.name, event)}>
Events: boardOpened, featureSubmitted, voted, commented, followed, error.
Troubleshooting
| You see | Why, and what to do |
|---|---|
| "Fewchurs isn't set up" | No key was passed. Check the env var name and restart the dev server. |
| "Invalid API key" (401) | The key is wrong. Copy it again from the dashboard. |
| "Invalid API key" (403) | The domain is not added to your app. The message names the domain to add. |
| "You're offline" | The request never reached Fewchurs. Check the network and press Try again. |
| The board has no styling | You forgot import "@fewchurs/react/styles.css". |
Outside production, every failed request is also logged once to the console as [fewchurs] ….
Server-safe entry
@fewchurs/react/core is the half with no React and no "use client" boundary: the fetch client, the
types, validation and error mapping. Use it in server code, workers or scripts.
More
- Full guide and examples: github.com/fewchurs/fewchurs-react
- Dashboard and docs: www.fewchurs.com
- Changelog: CHANGELOG.md
License
Proprietary. You may use the package in your own apps to connect them to Fewchurs and customize it through the documented props, CSS variables, slots and hooks. See LICENSE.