suo
Guides

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/react
import { 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

AttributePurpose
hostYour API host, for example https://api.usesuo.com
api-key / apiKeyYour public search key, or omit and pass scoped-token for a scoped, per-user token
index-name / indexNameWhich index to search
modemodal (⌘K, default) or inline. modal narrows to a full-screen sheet under 640px automatically.
placeholderInput 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.

On this page