fdback.iofdback.io

React Integration

React components and hooks for fdback.io

npm install @fdback.io/sdk react

Setup Provider

Wrap your app with the FdbackProvider:

// app/providers.tsx or app/layout.tsx
import { FdbackProvider } from "@fdback.io/sdk/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <FdbackProvider
      workspaceId="your-workspace-id"
      signEndpoint="/api/fdback/sign"
    >
      {children}
    </FdbackProvider>
  );
}

FeedbackButton Component

The easiest way to add feedback - a ready-to-use button:

"use client";
import { FeedbackButton } from "@fdback.io/sdk/react";

export function Header() {
  const user = useCurrentUser(); // Your auth hook

  return (
    <FeedbackButton
      user={{ email: user.email, name: user.name }}
      className="btn btn-primary"
      onOpen={(win) => console.log("Opened!", win)}
      onError={(err) => console.error(err)}
    >
      Give Feedback
    </FeedbackButton>
  );
}

FdbackWidget Component

Use FdbackWidget when you want the embedded floating widget in a React or Next.js app:

"use client";
import { FdbackWidget } from "@fdback.io/sdk/react";

export function AppWidget() {
  return (
    <FdbackWidget
      workspaceId="your-workspace-id"
      signEndpoint="/api/fdback/sign"
      mode="full"
      tabs={["feedback", "roadmap", "changelog"]}
      showBoardLink={true}
      theme="auto"
      colors={{
        primary: "#6366f1",
        light: {
          background: "#ffffff",
          foreground: "#111827",
        },
        dark: {
          background: "#111827",
          foreground: "#f9fafb",
        },
      }}
    />
  );
}

Set showLauncher={false} if you want to render your own trigger and control the widget with open / onOpenChange.

Set showBoardLink={true} to show an Open board link inside the widget. If the widget is authenticated through signEndpoint, the link uses the same signed login flow as the Core SDK so the user is logged in on the board too.

colors accepts hex values and valid CSS color strings such as oklch(...). When using oklch(...) for primary, set primaryForeground explicitly because automatic foreground contrast is only derived from hex colors.

useFdbackLogin Hook

For custom implementations with loading and error states:

"use client";
import { useFdbackLogin } from "@fdback.io/sdk/react";

export function CustomFeedback() {
  const { login, isLoading, error } = useFdbackLogin();

  const handleClick = async () => {
    await login(
      { email: "user@example.com", name: "John" },
      { mode: "popup" }
    );
  };

  return (
    <button onClick={handleClick} disabled={isLoading}>
      {isLoading ? "Opening..." : "Feedback"}
    </button>
  );
}

useFdback Hook

Access the Fdback context directly:

"use client";
import { useFdback } from "@fdback.io/sdk/react";

export function FeedbackStatus() {
  const { isOpen, getBoardUrl, workspaceId } = useFdback();

  return (
    <div>
      <p>Workspace: {workspaceId}</p>
      <p>Board URL: {getBoardUrl()}</p>
      <p>Popup open: {isOpen ? "Yes" : "No"}</p>
    </div>
  );
}

API Reference

ExportTypeDescription
FdbackProviderComponentContext provider with workspace config
FeedbackButtonComponentReady-to-use button with built-in signing
FdbackWidgetComponentEmbedded floating widget
useFdbackHookAccess context (client, isOpen, etc.)
useFdbackLoginHookLogin + open with loading/error state
useWidgetHookProgrammatic control for the embedded widget

FdbackProvider Props

interface FdbackProviderProps {
  workspaceId: string;      // Your workspace ID
  signEndpoint?: string;    // API endpoint for signing (e.g., "/api/fdback/sign")
  baseUrl?: string;         // Custom base URL
  children: React.ReactNode;
}

FeedbackButton Props

interface FeedbackButtonProps {
  user: FdbackUser;                    // User data to sign
  mode?: "popup" | "tab" | "redirect"; // How to open (default: "popup")
  onOpen?: (window: Window | null) => void;
  onError?: (error: Error) => void;
  className?: string;
  children?: React.ReactNode;
}

FdbackWidget Props

interface FdbackWidgetProps {
  workspaceId: string;
  baseUrl?: string;
  mode?: "simple" | "full";
  position?: "bottom-right" | "bottom-left" | "top-right" | "top-left";
  tabs?: ("feedback" | "roadmap" | "changelog")[];
  showBoardLink?: boolean;
  primaryColor?: string;
  colors?: WidgetThemeColors;
  launcherIcon?: string;
  theme?: "auto" | "dark" | "light";
  width?: number;
  height?: number;
  signEndpoint?: string;
  user?: { email: string; name?: string };

  open?: boolean;
  onOpenChange?: (open: boolean) => void;
  showLauncher?: boolean;

  onFeedbackSubmitted?: (feedback: { id: string }) => void;
  onTabChange?: (tab: string) => void;
  onAuthenticated?: (user: { id: string; email: string; name?: string | null }) => void;
}

interface WidgetThemeColors extends WidgetThemeColorTokens {
  light?: WidgetThemeColorTokens;
  dark?: WidgetThemeColorTokens;
}

interface WidgetThemeColorTokens {
  primary?: string;
  primaryForeground?: string;
  background?: string;
  foreground?: string;
  card?: string;
  cardForeground?: string;
  popover?: string;
  popoverForeground?: string;
  muted?: string;
  mutedForeground?: string;
  accent?: string;
  accentForeground?: string;
  border?: string;
  input?: string;
  ring?: string;
}

On this page