@nimbus-sh/react
v0.4.2
Published
React component for embedding a Nimbus terminal in your app. <NimbusTerminal /> is a typed iframe wrapper with token + tenant props.
Maintainers
Readme
@nimbus-sh/react
Put a Nimbus terminal in a React app.
<NimbusTerminal /> renders the hosted session shell, attached to a session
your backend minted a token for.
Install
npm install @nimbus-sh/react @nimbus-sh/sdk reactreact is a peer-dep (>=18) so the embedder's React copy is the
only one loaded.
Quickstart
import { NimbusTerminal } from '@nimbus-sh/react';
import { useEffect, useState } from 'react';
export function App() {
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
// Embedder's own endpoint mints the token from JWT_SECRET in env.
fetch('/api/auth/mint', { method: 'POST',
body: JSON.stringify({ tenant: 'acme', sub: 'alice' }) })
.then(r => r.json())
.then(({ token }) => setToken(token));
}, []);
if (!token) return <div>Loading…</div>;
return (
<NimbusTerminal
endpoint="https://my-nimbus.workers.dev"
token={token}
tenant="acme"
sub="alice"
onReady={() => console.log('session attached')}
style={{ width: '100%', height: 500 }}
/>
);
}Props
| Prop | Type | Required | Default | What |
|---|---|---|---|---|
| endpoint | string | ✓ | — | Base URL of your Nimbus deploy. |
| token | string | ✓ | — | JWT from issueNimbusToken. |
| tenant | string | ✓ | — | Embedder metadata; keep it aligned with the token's tn claim. The Worker trusts the token. |
| sub | string | | — | Embedder metadata; keep it aligned with the token's sub claim when present. |
| sessionId | string | | — | Attach to existing session. Absent → mint via /new. |
| onReady | () => void | | — | Fired when WS connects + first prompt visible. |
| onError | (e: NimbusTerminalError) => void | | — | Fired on session-side errors. |
| style | CSSProperties | | {width:'100%',height:'100%'} | Inline iframe styles. |
| className | string | | — | Extra class on the iframe. |
| sandbox | string | | allow-scripts allow-same-origin allow-downloads allow-forms allow-popups allow-popups-to-escape-sandbox | iframe sandbox attribute. allow-popups-to-escape-sandbox lets a preview opened in its own tab leave the sandbox, which an app that asks for cross-origin isolation needs: a sandboxed top-level page cannot be isolated. Exported as NIMBUS_TERMINAL_SANDBOX to extend. |
| title | string | | Nimbus terminal | Accessibility title. |
Imperative handle
import { useRef } from 'react';
import { NimbusTerminal, type NimbusTerminalRef } from '@nimbus-sh/react';
const ref = useRef<NimbusTerminalRef>(null);
<NimbusTerminal ref={ref} … />
<button onClick={() => ref.current?.reload()}>Reset session</button>ref.current exposes:
reload()— force-fetch the iframe.getUrl()— current attach URL.getElement()— the underlying<iframe>HTMLElement.
Headless hook: useNimbusSession()
For embedders that want their own UI:
import { useRef } from 'react';
import { useNimbusSession } from '@nimbus-sh/react';
function MyTerm({ token }: { token: string }) {
const iframeRef = useRef<HTMLIFrameElement | null>(null);
const { ready, attachUrl, error } = useNimbusSession({
endpoint: 'https://my-nimbus.workers.dev',
token,
iframeRef,
});
if (error) return <div>Error: {error.message}</div>;
if (!attachUrl) return null;
// The iframe mounts at once: the shell inside it is what reports ready.
return (
<div style={{ position: 'relative', height: 400 }}>
<iframe ref={iframeRef} src={attachUrl} style={{ width: '100%', height: '100%', border: 'none' }} />
{!ready && <div style={{ position: 'absolute', inset: 0 }}>Loading…</div>}
</div>
);
}iframeRef scopes the hook to its own iframe's events. Identity (tenant,
sub) belongs to the token; only <NimbusTerminal /> takes it, to show on
its iframe.
Why an iframe
- The xterm shell ships once from Nimbus, so no embedder pays bundle bloat.
- Cross-origin isolation: embedder JS cannot read the WebSocket.
- The shell already handles keybindings, resize, and CSP quirks. A React component would duplicate that logic.
MIT.
