Messages are labelled Receive and Send for readers, instead of the send and receive of the documented application, the sidebar shows them as icons.
A connection bar shows the channel address with the server below it, brokers label the address as a topic, queue or subject.
Messages are listed in an accordion, their examples beside the payload and headers on wide pages.
Example cards are titled with the name and summary of examples, selects switch to other examples and to their headers.
Protocol details only show the bindings of the selected server, x-* bindings are hidden.
A playground connects to channels, sends messages from their examples and identifies the received ones.
The playground edits address parameters in its URL and previews the URL to connect.
Code samples beside operations in JavaScript and Python for WebSocket, MQTT, Kafka, AMQP and NATS servers, and from x-codeSamples of operations.
Playground transports connect by protocol: WebSocket is built in, sseTransport receives Server-Sent Events.
The playground sends text, hex and Base64 messages, and previews binary ones in hex.
Security schemes show OAuth 2.0 flows, scopes and SASL mechanisms.
Avro, Protobuf and RAML schemas are shown as they are.
Fixes
Later traits override earlier ones, as the spec merges them in order.
defaultContentType applies to messages without contentType.
per: 'tag' matches tags by name, operations without tags are under unknown.
groupBy: 'channel' names folders by channel keys and files by operation ids.
Channels with empty servers are available on all servers.
Operations sharing a title on one page get unique anchors.
AsyncAPI 2 documents throw an error instead of generating no pages.
imports: [] no longer adds an empty line to generated files.
Operations show the description of their channel, it is in search and Markdown too.
readOnly properties are hidden from messages readers send and writeOnly ones from messages they receive, in schemas, TypeScript types and generated examples, instead of both from all messages.
API changes
Before
Now
slots.server and slots.channel of renderOperationLayout
slots.connection
content.renderAPIExampleUsageTabs
removed, examples are in messages
useOperationSecurity() returns schemes of operation or server
{ server, operation }, both apply
payload and headers of OperationMessage are schemas
{ schema, schemaFormat? }
OperationReply.messages have title and payload
OperationMessage[]
action prop of <Operation /> and <OperationProvider />
removed, read from the operation
preloaded.proxyUrl of AsyncAPIPageProps_Preloaded
removed, it was never used
meta.groupStyle of generateFiles()
removed, use folderStyle
Added the playground option of createAsyncAPIPage() with transports, and usePlayground(), usePlaygroundTransport() and sseTransport from @fumadocs/asyncapi/playground.
Added the generateTypeScriptDefinitions option, payloads and headers can be copied as TypeScript types.
Added the codeUsages option and slots.usage of renderOperationLayout, with createCodeUsageGeneratorRegistry() and registerDefaultCodeUsages() from @fumadocs/asyncapi/ui.
Added getText() to the data of AsyncAPI pages, their operations in Markdown for LLMs.
Added received to OperationMessage, whether readers receive the message.
All security schemes in the API playground
Support OAuth 2.0 deviceAuthorization flows, openIdConnect schemes and PKCE.
OAuth requests with a client secret and device flows go through proxyUrl when set, allow your authorization server in allowedOrigins.
The OAuth panel remembers the client ID.
mutualTLS schemes no longer send an Authorization header.
Headless: useOpenIdConnectFlows(), stf and returned of usePlaygroundAuth(), requestOAuthToken() accepts onUserCode, signal and proxyUrl.
Playgrounds on a page share their auth values, useAuthFields().mapValues() reads them from the page.
The playground reopens after OAuth flows return in client-rendered sites.
Returning OAuth flows no longer switch the security requirement of other playgrounds.
Added translation keys to @fumadocs/language.
Share @fumari/stf and @fumadocs/json-schema with installed UI
They are depended on with a caret range instead of an exact version, so UI installed with Fumadocs CLI can share one copy with the package.
Redesign the example request and response
Titled cards with selects instead of tabs, for the language, the response status and the examples of webhooks.
A Schema switch shows the JSON Schema of example responses.
Webhook examples show their body and parameters in sections instead of accordions.
The playground shows its code usages under a Request header, in the language selected on the page.
The playground shows response descriptions in full, in the Response header.
Added translation keys to @fumadocs/language.
Fix inline code samples with a function source
x-codeSamples and generateCodeSamples with a function as source rendered an empty code sample.
Fix the sticky example column
The example column sat under the header of Notebook layouts, and could be taller than the viewport.
Hide internal APIs
generatePythonObject() of fumadocs-openapi/requests/generators/python.
InternalOpenAPIMeta of fumadocs-openapi/server, and _getWatchPaths() of the OpenAPI server.
The Awaitable and DistributiveOmit types.
subscribe() of usePlaygroundAuth(), listen to the auth values in its stf instead.
Files under fumadocs-openapi/css/ other than preset.css.
Optional allowedOrigins in createProxy()
Without allowedOrigins, the proxy accepts any public origin instead of its own origin, and refuses hosts on private networks (Node.js and Deno).
Without allowedOrigins, cookies of your site and Set-Cookie headers of responses are not forwarded.
Proxied responses can't run scripts on your site, and their headers that apply to your site (e.g. Strict-Transport-Security, Clear-Site-Data) are removed.
Redirects to other origins drop the Authorization, Proxy-Authorization and Cookie headers, like fetch().
Remove all Access-Control-* headers of responses, some were kept before.
Abort the proxied request when the client disconnects.
Forward request bodies without a Content-Length header, and read them once.
Respond with 502 instead of 500 to upstream statuses outside 200-599 (e.g. 999).
Use prose-sm and prose-xs for small prose
Small prose in TOC items, type tables, API descriptions and AI chat scales its code and headings with the text.
All security schemes in the API playground
Support OAuth 2.0 deviceAuthorization flows, openIdConnect schemes and PKCE.
OAuth requests with a client secret and device flows go through proxyUrl when set, allow your authorization server in allowedOrigins.
The OAuth panel remembers the client ID.
mutualTLS schemes no longer send an Authorization header.
Headless: useOpenIdConnectFlows(), stf and returned of usePlaygroundAuth(), requestOAuthToken() accepts onUserCode, signal and proxyUrl.
Playgrounds on a page share their auth values, useAuthFields().mapValues() reads them from the page.
The playground reopens after OAuth flows return in client-rendered sites.
Returning OAuth flows no longer switch the security requirement of other playgrounds.
Added translation keys to @fumadocs/language.
Redesign the example request and response
Titled cards with selects instead of tabs, for the language, the response status and the examples of webhooks.
A Schema switch shows the JSON Schema of example responses.
Webhook examples show their body and parameters in sections instead of accordions.
The playground shows its code usages under a Request header, in the language selected on the page.
The playground shows response descriptions in full, in the Response header.
Added translation keys to @fumadocs/language.
@fumadocs/base-ui@16.17.4
fumadocs-core@16.17.4
fumadocs-ui@16.17.4
Keyboard-scrollable MDX tables
Tables of defaultMdxComponents are focusable, so keyboard users can scroll wide tables in Safari.
Docs Layout: layout tabs with tabMode: 'top' no longer cover the page.
Glass Layout: sidebar items are not all active with a page tree without $id.
Glass Layout: icons of layout tabs are sized correctly with the default tabs option.
Faster loader()
Page trees are built faster, especially with custom sort options.
Faster loader() setup and page lookups like getPage() and getPageByUrl().
Fallback page trees of i18n sources keep the locale in URLs and IDs.
A page listed in pages is no longer duplicated when another folder takes it with a higher priority, like pagesIndex.
Redesigned story controls
Props are edited in rows like the OpenAPI playground, nested objects and arrays open in a panel with breadcrumbs.
Reset the props to the defaults of the variant.
fixed values hide their controls with the Vite plugin and Turbopack loader too.
Switching back to a variant restores its default values.
getDefaultValue() leaves optional properties unset, typeToString() prints enums as their members.
Updated translation keys of the controls, see @fumadocs/language for the new ones.
Story frames
New frame option of defineStory(), renders components filling the viewport (e.g. layouts) in an iframe, scaled to fit the panel. Its Container wraps the frame, like a window.
story.Frame renders the component on the frame page, with the arguments from the story panel.
Story components can be any component type, like lazy ones that only the frame page loads.
useStoryFrame() connects your own panel to the frame.
Redesigned story controls
Props are edited in rows like the OpenAPI playground, nested objects and arrays open in a panel with breadcrumbs.
Reset the props to the defaults of the variant.
fixed values hide their controls with the Vite plugin and Turbopack loader too.
Switching back to a variant restores its default values.
getDefaultValue() leaves optional properties unset, typeToString() prints enums as their members.
Updated translation keys of the controls, see @fumadocs/language for the new ones.
@fumadocs/base-ui@16.17.1
fumadocs-core@16.17.1
fumadocs-ui@16.17.1
Format generated Markdown tables
Generated tables have aligned columns: the type tables of auto-type-table, the tables of renderToMarkdown() and the table rows of search records.
markdownTable() from fumadocs-core/mdx-plugins/stringifier creates a formatted table for your plugins.
Structured data records each table row as a Markdown table of its header row and itself, instead of a record per cell. Type tables from auto-type-table record a row for each prop instead of the TypeTable element. Re-sync your search indexes to pick them up.
remarkStructure() defaults types to table instead of tableCell.
tableRowToStructuredData() from fumadocs-core/search creates the structured data of a table row, typeTableToStructuredData() from fumadocs-typescript of a type table.
Search hooks group the rows of a table into a table item, <SearchDialogList /> renders it with Table, <SearchDialogListTable /> by default.
Algolia and Orama Cloud link to the anchor of every record, like the props of type tables.
Orama Cloud searches title, section and content by default, set params.properties to search other fields.
remarkStructure() of Sätteri records the data.structuredData of nodes in place of the nodes.
Fix images in descriptions, show the OAuth redirect URI
Images in Markdown of API pages, like the description of an operation, and in descriptions of <AutoTypeTable /> props no longer crash the page with "Element type is invalid".
The OAuth panel of the playground shows the redirect_uri of the authorization code and implicit flows, with a button to copy it: the oauthRedirectUrl route when set, otherwise the current page.
The Authorize row of OAuth schemes in the playground is one button, filling the row.
Markdown and search records from the authored source
remarkLLMs() and remarkStructure() of fumadocs-core slice their Markdown from the authored source like Sätteri, instead of stringifying the syntax tree. It is much faster, Markdown is no longer escaped or reformatted, and local images keep their addresses. Re-sync your search indexes to pick up the new records.
Plugins record the Markdown of content they replace with replaceSource() or embedSource() from fumadocs-core/mdx-plugins/stringifier, in place of data._stringify, and add search records with data.structuredData. Nodes they insert otherwise are left out. A namespace limits an edit to the stringifiers of that namespace, like search for search records.
Search records are always Markdown, also in Sätteri. filterElement replaces stringify.filterElement, it chooses the JSX elements kept as HTML tags (File, TypeTable, Callout and Card by default) that search dialogs render as components. Other elements and links are replaced by their content, images are removed, and an element on one line is recorded like a paragraph.
Removed defaultStringifier() (use createStringifier()), StringifyOptions, allowedMdxAttributes, filterMdxAttributes, placeholder() (use mdxAsPlaceholder), and the stringify and mdast-util-to-markdown options of both plugins.
Included content goes through the plugins like the document's own, Sätteri includes .md files as Markdown.
<auto-files> shows its files in a code block, auto-type-table its props in a Markdown table, created by typeTableToMarkdown() from fumadocs-typescript.
remarkShow() and fileGenerator() of fumadocs-docgen record their Markdown, generators receive the file to do the same.
Records of fumadocs-obsidian resolve wikilinks, and leave comments, block IDs, callout markers and embeds out. Comments are removed before parsing, so they no longer split a paragraph.
Pages of fumadocs-python compile from their MDX, so they have Markdown and search records.
fumadocs-mdx, fumadocs-docgen and fumadocs-obsidian require fumadocs-core 16.17.0.
Types longer than 500 characters in hover popups are truncated by the checker (... 26 more ...) instead of printed in full, so pages with large object types compile to much smaller MDX.
Code blocks are briefly written to the .twoslash directory while being analyzed, instead of going through filesystem callbacks, which makes the analysis about 2x faster. Add .twoslash to your .gitignore.
Identical popups of a code block are highlighted once.
Search results no longer wrap matches in <mark>, content is the indexed Markdown. The search dialog highlights matches with the CSS Custom Highlight API, style them with ::highlight(fd-search). Custom search UIs can use useHighlightQuery() from fumadocs-core/search/client.
createContentHighlighter() is deprecated.
Removed contentWithHighlights from search results, and the renderHighlights prop of <SearchDialogListItem />.
<SearchDialogListItem /> renders the Markdown of results with the prose prose-sm typography.
Search hooks for each provider
fumadocs-core/search/client exports a hook for each search client, like useFetchSearch(). They return the props of <SearchDialog />:
data is the last successful search, its items have their content parsed into hastContent. error is set when the last search failed.
experimental_useSearch() creates a search hook from a memoized search function.
useDocsSearch() is deprecated.
useFlexsearchStatic() and useOramaCloudLegacySearch() are exported from the paths of their clients.
<SearchDialogList /> shows defaultItems without results.
useSearchList() is removed, useSearch() returns getActive(), setActive() and subscribeActive() for the active item.
<SearchDialogListItem /> renders a div instead of a button, table rows render their cells only.
renderMarkdown of <SearchDialogListItem /> renders content instead of hastContent. Without it, the string content of custom items is shown as text.
The templates of Fumadocs CLI and Create Fumadocs App use the new hooks.
Index tables by row
Structured data records each table row as a Markdown table of its header row and itself, instead of a record per cell. Type tables from auto-type-table record a row for each prop instead of the TypeTable element. Re-sync your search indexes to pick them up.
remarkStructure() defaults types to table instead of tableCell.
tableRowToStructuredData() from fumadocs-core/search creates the structured data of a table row, typeTableToStructuredData() from fumadocs-typescript of a type table.
Search hooks group the rows of a table into a table item, <SearchDialogList /> renders it with Table, <SearchDialogListTable /> by default.
Algolia and Orama Cloud link to the anchor of every record, like the props of type tables.
Orama Cloud searches title, section and content by default, set params.properties to search other fields.
remarkStructure() of Sätteri records the data.structuredData of nodes in place of the nodes.
Show page tree roots on fallback pages
On pages from the fallback page tree, layout tabs list the root folders of the main page tree again.
Restore sync index() and indexNode() in llms()
Since 16.15.9, index() and indexNode() of llms() returned a promise, so code using them as strings, like joining indexNode() results, printed [object Promise] without a type error. They return a string again when llms() receives a loader, and only return a promise when it receives a function like getSource of runtime content sources. Awaiting them keeps working in both cases.
Markdown and search records from the authored source
remarkLLMs() and remarkStructure() of fumadocs-core slice their Markdown from the authored source like Sätteri, instead of stringifying the syntax tree. It is much faster, Markdown is no longer escaped or reformatted, and local images keep their addresses. Re-sync your search indexes to pick up the new records.
Plugins record the Markdown of content they replace with replaceSource() or embedSource() from fumadocs-core/mdx-plugins/stringifier, in place of data._stringify, and add search records with data.structuredData. Nodes they insert otherwise are left out. A namespace limits an edit to the stringifiers of that namespace, like search for search records.
Search records are always Markdown, also in Sätteri. filterElement replaces stringify.filterElement, it chooses the JSX elements kept as HTML tags (File, TypeTable, Callout and Card by default) that search dialogs render as components. Other elements and links are replaced by their content, images are removed, and an element on one line is recorded like a paragraph.
Removed defaultStringifier() (use createStringifier()), StringifyOptions, allowedMdxAttributes, filterMdxAttributes, placeholder() (use mdxAsPlaceholder), and the stringify and mdast-util-to-markdown options of both plugins.
Included content goes through the plugins like the document's own, Sätteri includes .md files as Markdown.
<auto-files> shows its files in a code block, auto-type-table its props in a Markdown table, created by typeTableToMarkdown() from fumadocs-typescript.
remarkShow() and fileGenerator() of fumadocs-docgen record their Markdown, generators receive the file to do the same.
Records of fumadocs-obsidian resolve wikilinks, and leave comments, block IDs, callout markers and embeds out. Comments are removed before parsing, so they no longer split a paragraph.
Pages of fumadocs-python compile from their MDX, so they have Markdown and search records.
fumadocs-mdx, fumadocs-docgen and fumadocs-obsidian require fumadocs-core 16.17.0.
remarkImage() with onError: 'hide' removes the right images when a paragraph has several, and Sätteri removes them from the Markdown too.
files code blocks of remarkMdxFiles() nest the entries under the last item of a folder (after └──), and trees indented with spaces only.
The remark and rehype plugins no longer slow down quadratically on large documents, like rehypeToc() taking 17 ms instead of 239 ms on a 5 MB page.
fumadocs-epub removes every unresolved image, the second of two adjacent ones was kept.
Sätteri: headings with expression props, like <Badge value={1} /> or local images, compile again, without these elements in their toc entry.
Sätteri: remarkStructure() records every node type listed in types, like fumadocs-core. A blockquote is one search record instead of two. In the Markdown, includes and type tables stay inside their list item or blockquote, heading IDs no longer break setext and closed ATX headings, and nested replacements no longer duplicate the source after them.
Sync Mixedbread stores with sync()
sync() and toDocuments() from fumadocs-core/search/mixedbread upload a file for each page, whose chunks are its title, headings and paragraphs. Results link to their headings and render tables like other search integrations.
Stores synced with mxbai store sync need a re-sync, the frontmatter of pages is no longer read.
Tag filters match the tags of pages, locale filters results by language, and the limit of requests can only lower topK.
The Mixedbread template of Fumadocs CLI syncs a pre-rendered static.json with sync(), debounces searches by 300 ms, and reads the API key from MXBAI_API_KEY.
Ignore unsupported locale cookies
With hideLocale: 'always', createI18nMiddleware() ignores locale cookies that aren't in languages.
Limit results of the advanced search server
Without a limit in the request, it returns up to 60 results instead of every matched record.
The limit in its search option applies to requests without one.