Install: React, Next, fumadocs and plain HTML
Add the widget with one script tag, or one line of React, for every framework suo supports today.
The widget is a web component (<suo-search>) with a thin React wrapper. Every install method loads the same underlying widget — pick whichever matches your stack.
Plain HTML
<script src="https://cdn.usesuo.com/widget@1.js" async></script>
<suo-search host="https://api.usesuo.com" api-key="suo_search_YOUR_KEY" index-name="docs"></suo-search>widget@1.js is an auto-updating alias with no integrity hash. Pin an exact version with Subresource Integrity if your deployment requires it — see "Pin a version" below.
React
npm install @suo/reactimport { SuoSearch } from '@suo/react';
export function Header() {
return <SuoSearch host="https://api.usesuo.com" apiKey="suo_search_YOUR_KEY" indexName="docs" />;
}@suo/react is a client-only wrapper — render it inside a component your framework does not server-render, or guard it behind a mount check if your setup requires that explicitly.
Next.js
'use client';
import { SuoSearch } from '@suo/react';
export function SiteSearch() {
return <SuoSearch host="https://api.usesuo.com" apiKey="suo_search_YOUR_KEY" indexName="docs" />;
}Mark the component 'use client' in the App Router.
fumadocs
fumadocs renders search through a SearchDialog component you supply to RootProvider, not a plain child — wrap <SuoSearch> in one:
import type { SharedProps } from 'fumadocs-ui/contexts/search';
import { SuoSearch } from '@suo/react';
function SuoSearchDialog({ open, onOpenChange }: SharedProps) {
if (!open) return null;
return (
<div className="suo-docs-search-overlay" onClick={() => onOpenChange(false)}>
<SuoSearch
host="https://api.usesuo.com"
apiKey="suo_search_YOUR_KEY"
indexName="docs"
mode="inline"
onClick={(event) => event.stopPropagation()}
/>
</div>
);
}import { RootProvider } from 'fumadocs-ui/provider';
export default function Layout({ children }: { children: React.ReactNode }) {
return <RootProvider search={{ SearchDialog: SuoSearchDialog }}>{children}</RootProvider>;
}This app (apps/docs) does exactly this for its own search, including the escape-to-close and focus handling a real dialog needs — see app/components/suo-search-dialog.tsx and app/routes/site.tsx for the full wiring.
Attributes shared by every install
| Attribute | Purpose |
|---|---|
host | Your API host, for example https://api.usesuo.com |
api-key / apiKey | Your public search key, or omit and pass scoped-token for a scoped, per-user token |
index-name / indexName | Which index to search |
mode | modal (⌘K, default) or inline. modal narrows to a full-screen sheet under 640px automatically. |
placeholder | Input placeholder text |
See the full widget reference for every attribute and method.
Recent searches live in the visitor's browser
The widget keeps each visitor's recent searches and recently viewed results in
localStorage, scoped to your index name, so it can show them again on their
next visit. Nothing here is sent to suo or to your own servers — it never
leaves the visitor's browser. If you publish a privacy policy for your own
site or app, mention that recent search terms are stored locally in the
visitor's browser.
Pin a version
For a deployment that needs Subresource Integrity or a frozen widget version:
<script
src="https://cdn.usesuo.com/widget@1.4.2.js"
integrity="sha384-…"
crossorigin="anonymous"
async
></script>Exact versions are retained on the CDN indefinitely; the @1 alias always points at the newest 1.x release.