Package Exports
- @perspective-ai/sdk-react
Readme
@perspective-ai/sdk-react
React hooks and components for Perspective AI.
Not using React? Use
@perspective-ai/sdkfor vanilla JavaScript.
Installation
npm install @perspective-ai/sdk-reactPeer Dependencies: React 18+ or 19+
Quick Start
import { usePopup } from "@perspective-ai/sdk-react";
function App() {
const { open } = usePopup({
researchId: "your-research-id",
onSubmit: () => console.log("Interview completed!"),
});
return <button onClick={open}>Give Feedback</button>;
}API Overview
| API | Type | Description |
|---|---|---|
usePopup |
Hook | Open popup modal programmatically |
useSlider |
Hook | Open slider panel programmatically |
useFloatBubble |
Hook | Floating chat bubble lifecycle |
Widget |
Component | Inline embed in a container |
Fullpage |
Component | Full viewport takeover |
FloatBubble |
Component | Convenience wrapper for useFloatBubble |
Mental Model:
- Hooks for overlays (popup, slider, float bubble) - you control the trigger
- Components for embeds (widget, fullpage) - render inline DOM
Hooks
usePopup
Open a popup modal with your own trigger element.
import { usePopup } from "@perspective-ai/sdk-react";
function App() {
const { open, close, isOpen } = usePopup({
researchId: "your-research-id",
onSubmit: () => console.log("Done!"),
});
return (
<>
<button onClick={open}>Take Survey</button>
{isOpen && <span>Survey is open</span>}
</>
);
}Programmatic trigger:
const { open } = usePopup({ researchId: "xxx" });
useEffect(() => {
if (userCompletedCheckout) {
open();
}
}, [userCompletedCheckout, open]);Controlled mode:
const [isOpen, setIsOpen] = useState(false);
const popup = usePopup({
researchId: "xxx",
open: isOpen,
onOpenChange: setIsOpen,
});
// External control
<button onClick={() => setIsOpen(true)}>Open from anywhere</button>;useSlider
Open a slider panel with your own trigger element.
import { useSlider } from "@perspective-ai/sdk-react";
function App() {
const { open, close, isOpen } = useSlider({
researchId: "your-research-id",
});
return <button onClick={open}>Open Feedback Panel</button>;
}useFloatBubble
Manage a floating chat bubble lifecycle.
import { useFloatBubble } from "@perspective-ai/sdk-react";
function App() {
const { open, close, isOpen } = useFloatBubble({
researchId: "your-research-id",
});
// Bubble mounts on component mount
// Use open/close for programmatic control
return null;
}Components
Widget
Inline embed that renders in a container.
import { Widget } from "@perspective-ai/sdk-react";
<Widget
researchId="your-research-id"
onSubmit={() => console.log("Done!")}
className="my-widget"
style={{ height: 600 }}
/>;Fullpage
Full viewport takeover embed.
import { Fullpage } from "@perspective-ai/sdk-react";
<Fullpage researchId="your-research-id" />;FloatBubble
Convenience wrapper around useFloatBubble hook.
import { FloatBubble } from "@perspective-ai/sdk-react";
<FloatBubble researchId="your-research-id" />;Hook Options
All hooks accept options from EmbedConfig:
interface UsePopupOptions {
researchId: string;
host?: string;
theme?: "light" | "dark" | "system";
params?: Record<string, string>;
brand?: {
light?: {
primary?: string;
secondary?: string;
bg?: string;
text?: string;
};
dark?: { primary?: string; secondary?: string; bg?: string; text?: string };
};
// Callbacks
onReady?: () => void;
onSubmit?: (data: { researchId: string }) => void;
onClose?: () => void;
onNavigate?: (url: string) => void;
onError?: (error: EmbedError) => void;
// Controlled mode
open?: boolean;
onOpenChange?: (open: boolean) => void;
}Hook Return Types
interface UsePopupReturn {
open: () => void;
close: () => void;
toggle: () => void;
isOpen: boolean;
handle: EmbedHandle | null;
}
interface UseSliderReturn {
open: () => void;
close: () => void;
toggle: () => void;
isOpen: boolean;
handle: EmbedHandle | null;
}
interface UseFloatBubbleReturn {
open: () => void;
close: () => void;
toggle: () => void;
unmount: () => void;
isOpen: boolean;
handle: FloatHandle | null;
}Other Hooks
useThemeSync
Sync theme between your app and embedded interviews:
import { useThemeSync } from "@perspective-ai/sdk-react";
function App() {
const [theme, setTheme] = useState<"light" | "dark">("light");
// Syncs theme changes to all active embeds
useThemeSync(theme);
return (
<button onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}>
Toggle Theme
</button>
);
}TypeScript
All types are exported:
import type {
// Hook types
UsePopupOptions,
UsePopupReturn,
UseSliderOptions,
UseSliderReturn,
UseFloatBubbleOptions,
UseFloatBubbleReturn,
// Component types
WidgetProps,
FloatBubbleProps,
FullpageProps,
} from "@perspective-ai/sdk-react";
// Re-exported from @perspective-ai/sdk
import type {
EmbedConfig,
EmbedHandle,
FloatHandle,
BrandColors,
ThemeValue,
EmbedError,
} from "@perspective-ai/sdk-react";SSR Safety
All hooks and components are SSR-safe and include the "use client" directive. Works with Next.js, Remix, and other React frameworks.
License
MIT