Framework guide

Feature-request board for Remix

Feedback is a React client component. Mount it from a Remix client route or a client-only island. Pass user from your session loader, Feedback does not authenticate board end users. Scope is embed-only; there is no public board URL.

Install

pnpm add @bootstrapware/feedback

Import @bootstrapware/feedback/styles.css from the client module that renders the board (or from your root stylesheet if you prefer one global import).

Client island

import { Feedback, createLocalAdapter } from "@bootstrapware/feedback";
import "@bootstrapware/feedback/styles.css";

export function FeedbackBoard({ user }: { user: { id: string; name?: string } }) {
  return (
    <Feedback
      user={user}
      adapter={createLocalAdapter({ storageKey: "remix-feedback" })}
    />
  );
}

Mount <FeedbackBoard /> from a route that is already behind your session. Remix loaders stay for page data; BYO writes go through resource routes.

Loader → user prop

// app/routes/settings.ideas.tsx
export async function loader({ request }: LoaderFunctionArgs) {
  const session = await requireUserSession(request);
  return json({
    user: { id: session.userId, name: session.displayName },
  });
}

Pass that user into the client island. Opaque stable ids matter for voting, see identity.

BYO resource routes

Pass a FeedbackAdapter that hits your Remix resource routes. Authenticate the session cookie, re-bind authorship, enforce title ≤ 200 / body ≤ 5000, and store statuses as open | planned | in_progress | shipped | declined.

// Illustrative, your routes, your schema
export async function action({ request }: ActionFunctionArgs) {
  const session = await requireUserSession(request);
  const body = await request.json();
  // Create post / vote using session.userId, not body.author.id alone.
  return json({ ok: true });
}

Hosted configuration and env

Expose only publishable keys to the browser. Pattern depends on your Remix setup (classic window.ENV injection from the root loader, or Vite-based Remix env). Never ship bsw_*_sec_ to the client. Details: API keys.

<Feedback
  boardId={ENV.FEEDBACK_BOARD_ID}
  publishableKey={ENV.BSW_PUBLISHABLE_KEY}
  user={user}
/>

Mode resolution: explicit adapter → Hosted when boardId + publishable key → otherwise local.

Pitfalls

  • Rendering Feedback without a client boundary
  • Forgetting styles.css
  • Leaking secret keys through the root loader ENV blob
  • Trusting client author ids on resource routes
  • Using completed instead of shipped

Related: React guide · Next.js guide · Identity · Adapter · Quickstart