React SDK (@asgard-js/react)
@asgard-js/react builds on @asgard-js/core to provide a ready-made React chat UI and hooks, so a React application can integrate Asgard chat quickly.
Choosing an integration pattern, advanced configuration and common problems are covered in the frontend SDK guide, and every capability has a runnable example at SDK Demo.
Installation
@asgard-js/react takes @asgard-js/core as a peer dependency, so install both:
npm install @asgard-js/react @asgard-js/core
Importing the stylesheet
import "@asgard-js/react/style";
This line is needed once. Without it the chatbot renders unstyled.
The <Chatbot> component
import { Chatbot } from "@asgard-js/react";
import "@asgard-js/react/style";
export default function App() {
return (
<div style={{ height: "100vh" }}>
<Chatbot
title="My AI assistant"
customChannelId="user-123"
config={{
botProviderEndpoint:
"https://api.asgard-ai.com/ns/{namespace}/bot-provider/{botProviderId}",
}}
/>
</div>
);
}
Required props
| Prop | Type | Description |
|---|---|---|
config.botProviderEndpoint | string | The Bot Provider's endpoint URL |
customChannelId | string | The conversation channel's id, usually a user id or session id |
The full prop list is in the Props Reference.
SSR frameworks (Next.js)
@asgard-js/react depends on browser APIs (window, SpeechRecognition, ResizeObserver), so it cannot run on the server.
Next.js App Router
"use client";
import dynamic from "next/dynamic";
import "@asgard-js/react/style";
const Chatbot = dynamic(
() => import("@asgard-js/react").then((m) => m.Chatbot),
{ ssr: false },
);
export default function ChatPage() {
return (
<div style={{ height: "100vh" }}>
<Chatbot
title="My AI assistant"
customChannelId="user-123"
config={{
botProviderEndpoint:
"https://api.asgard-ai.com/ns/{namespace}/bot-provider/{botProviderId}",
}}
/>
</div>
);
}
Next.js Pages Router
import dynamic from "next/dynamic";
const Chatbot = dynamic(
() => import("@asgard-js/react").then((m) => m.Chatbot),
{ ssr: false },
);
Docusaurus / Gatsby
import BrowserOnly from "@docusaurus/BrowserOnly";
export default function MyPage() {
return (
<BrowserOnly>
{() => {
const { Chatbot } = require("@asgard-js/react");
require("@asgard-js/react/style");
return (
<Chatbot
title="..."
customChannelId="..."
config={{ botProviderEndpoint: "..." }}
/>
);
}}
</BrowserOnly>
);
}
Custom UI (useAsgardContext)
Inside custom render props such as renderHeader and renderFooter, useAsgardContext gives you the conversation state:
import { useAsgardContext } from "@asgard-js/react";
function CustomHeader() {
const { resetChannel, isConnecting } = useAsgardContext();
return (
<div>
<span>My Bot</span>
<button onClick={resetChannel} disabled={isConnecting}>
Reset conversation
</button>
</div>
);
}
Contexts and providers
@asgard-js/react exports four contexts, each with a provider and a hook. <Chatbot> wires them up internally; you only reach for them when assembling your own UI.
| Context | Provider | Hook | What it provides |
|---|---|---|---|
AsgardServiceContext | AsgardServiceContextProvider | useAsgardContext | Conversation state and actions (resetChannel, isConnecting) |
AsgardThemeContext | AsgardThemeContextProvider | useAsgardThemeContext | Theme settings, defaulting to defaultAsgardThemeContextValue |
AsgardTemplateContext | AsgardTemplateContextProvider | useAsgardTemplateContext | How message templates render |
AsgardAppInitializationContext | AsgardAppInitializationContextProvider | useAsgardAppInitializationContext | Application initialization state |
FileDropContextProvider and useFileDropContext handle drag-and-drop files.
ThemeScope applies a theme to one subtree, and DEFAULT_CONTENT_MAX_WIDTH is the content area's default maximum width.
Headless integration
To build your own interface instead of using <Chatbot>, start from these two hooks:
import { useAsgardServiceClient, useChannel } from '@asgard-js/react';
const client = useAsgardServiceClient({
config: { botProviderEndpoint, apiKey },
keepConnectionOnUnmount: false,
});
const channel = useChannel({ client, customChannelId, initMessages });
useAsgardServiceClient creates and manages the AsgardServiceClient lifecycle, returning AsgardServiceClient | null. keepConnectionOnUnmount decides whether the connection survives the component unmounting.
useChannel takes UseChannelProps (client, customChannelId, initMessages, autoResetChannel, onSseMessage, onAuthError and more) and returns UseChannelReturn.
File explorer and sandbox
Components and hooks for showing a sandbox filesystem:
| Export | Purpose |
|---|---|
FileExplorer / FileExplorerPanel | The explorer itself and its panel container |
FileExplorerProvider / useFileExplorer | The explorer's context and the hook that reads it |
useFileExplorerController | Builds the explorer's controller, taking UseFileExplorerControllerOptions |
FileView | Viewer for a single file |
createSandboxFsProviders | Wraps AsgardServiceClient's sandboxFs* methods into the provider set the explorer expects |
useSandboxLaunch / useLaunchedSandboxes | Launch a sandbox, and read the list of launched ones |
sandboxAsSource / sandboxesAsSources | Turn a sandbox into an explorer source |
SourceSetFileExplorer | The SourceSet explorer, paired with AsgardSourceSetClient from @asgard-js/core |
EMPTY_SOURCE_VIEW is the empty state used when there is no source.
Other components
ChatHeader is the conversation title bar, and ChatHeaderAction adds action buttons to it. TaskList and SubagentList render tasks and subagents from @asgard-js/core's derived state.
General React utilities
These hooks carry no Asgard-specific meaning. They are general-purpose helpers the package uses internally and exports along the way: you can use them, but they are not part of the integration surface. useDebounce, useDeepCompareMemo, useResizeObserver, useVisualViewport, useIsAtBottom, useSyncedSpin, usePromptSuggestion.
t is the i18n translation function and Locale is the locale type.
Sandbox browser panel
SandboxBrowserPanel renders a Sandbox's browser inside your layout and handles the connection, input forwarding and cursor itself.
useSandboxBrowserController({ open?, activeSandboxName? }) owns its open state and which Sandbox it points at. It returns open, activeSandboxName and requestedBrowser, plus openBrowser(), closeBrowser(), toggle(), selectSandbox(name) and requestBrowser(name, { reveal }). requestBrowser opens the panel as well by default; pass reveal: false to switch target without revealing it.
The returned object is memoised so its identity moves only with the state — the panel's connection effect depends on it, and a fresh object each render would reconnect every time.
toRemoteCoords(video, clientX, clientY) converts a pointer position on the panel into the remote screen's coordinates, and fromRemoteCoords(video, x, y) goes the other way. Both account for the video's letterboxing and return null rather than inventing a coordinate they cannot compute. You only call them directly when building your own pointer overlay or annotations.
Interactive demo
Every prop and capability (message templates, theming, custom rendering, authentication, tool calls) has a runnable example: sdk-demo.asgard-ai.com
Further reading
- Frontend SDK guide — pattern selection, props and common problems
- JavaScript SDK reference — the underlying
@asgard-js/coreAPI