Skip to main content

Web Component

@apiboost/omnispec ships a framework-agnostic Web Component (<omnispec-renderer>) alongside the React component. It is part of the free package — no additional install. Use it from vanilla HTML, Vue, Angular, Svelte, or any other framework that can render a DOM element.

Quick start​

The fastest path is the standalone bundle — a single self-contained <script> that ships React, ReactDOM, and the renderer inline, with no build step on the consumer side.

<!doctype html>
<html>
<body>
<script src="https://unpkg.com/@apiboost/omnispec@latest/dist/wc/standalone.js"></script>
<omnispec-renderer
spec-url="https://petstore3.swagger.io/api/v3/openapi.json"
></omnispec-renderer>
</body>
</html>

For framework apps, prefer the subpath import so React/ReactDOM are shared with your existing tree:

import '@apiboost/omnispec/wc'
// <omnispec-renderer> is now registered globally.

Two configuration paths​

Declarative HTML attributes​

Best for scalar config like URLs, enums, and booleans:

<omnispec-renderer
spec-url="https://example.com/openapi.json"
theme-base="auto"
display-mode="compact"
navigation-mode="grouped"
allow-try-it="true"
proxy-url="/api/proxy"
></omnispec-renderer>

Imperative property assignment​

Recommended for complex objects (parsed specs, theme overrides, sidebar nav):

import type { OmniSpecRendererElement } from '@apiboost/omnispec/wc'

const el = document.querySelector('omnispec-renderer') as OmniSpecRendererElement
el.spec = parsedSpecObject
el.theme = {
base: 'dark',
overrides: { '--omnispec-color-primary': '#8B5CF6' },
}
el.sidebarNav = {
items: [
{ id: 'home', label: 'Home', href: '/' },
],
}

You can also stringify-then-set the same complex props as JSON attributes — the element parses them with a try/catch and logs a console error on failure:

<omnispec-renderer
spec-url="/openapi.json"
theme='{"base":"dark"}'
></omnispec-renderer>

The imperative property always wins over an attribute when both are set.

Attribute reference​

AttributeTypeDescription
spec-urlstringURL to fetch the spec from.
specJSON stringInline spec content (object or string) — see properties.
theme-base'light' | 'dark' | 'auto'Theme base. 'auto' follows the system preference.
theme-togglebooleanShow the floating theme toggle in 'auto' mode. Defaults to true.
themeJSON stringFull ThemeConfig (use the property in JS).
sidebar-navJSON stringSidebar nav config (use the property in JS).
display-mode'compact' | 'reference'Layout mode.
navigation-mode'grouped' | 'segmented'Nav grouping.
layout'sidebar' | 'stacked'Page layout.
sidebar-position'left' | 'right'Sidebar placement.
try-it-layout'inline' | 'panel'Try-It position in compact mode (default panel). panel = sticky right column; inline = collapsed below the operation. Ignored in reference mode.
schema-style'lines' | 'tokens' | 'chain' | 'table' | 'card'Schema tree style. table and card require Pro.
allow-try-itbooleanEnable Try-It.
interactive-oauthbooleanOpt out of the Pro interactive OAuth flow with "false" (forces manual token paste). No effect without Pro.
default-expand-operationsbooleanExpand every operation on load.
proxy-urlstringTry-It proxy endpoint.
server-urlstringOverride the API base URL for Try-It, ignoring the spec's servers.
try-it-persist-ttlnumber (ms)How long to persist Try-It auth and inputs in the browser.
download-linkboolean or URLShow a download button — pass true to use the spec URL or a string to specify a different URL.
docs-urlstringURL for the upgrade prompt's docs link.
upgrade-urlstringURL for the upgrade prompt's upgrade link.

Boolean attributes are truthy by default: any value other than 'false', '0', or 'off' (case-insensitive) — including a bare attribute with no value — is treated as true. To disable a boolean, set it to false/0/off or leave the attribute unset.

Property reference​

For complex/JSON config, use the property API. Properties are available on the custom element after it has been created.

PropertyTypeDescription
specstring | objectURL, raw string, or parsed spec object.
themeThemeConfigFull theme config including overrides, onThemeChange.
sidebarNavSidebarNavConfigCustom sidebar navigation.

Events​

The element dispatches standard CustomEvents that bubble and are composed through the shadow boundary. The detail property carries the typed payload.

Eventdetail typeWhen
spec-loadedSpecLoadedInfo ({ title, version, type })After the spec has been fetched and parsed.
try-it-requestTryItRequestWhen the user clicks "Try it" — payload of the outgoing request.
try-it-responseTryItResponseWhen the Try-It response is received.
el.addEventListener('spec-loaded', (e) => {
console.log((e as CustomEvent).detail) // { title, version, type }
})

Shadow DOM​

The element uses open shadow DOM. You can inspect it via el.shadowRoot for debugging. The renderer's styles are isolated from your page — host page CSS does not leak in, and renderer styles do not leak out.

Design tokens cascade in​

CSS custom properties inherit through shadow boundaries, so design tokens defined on the host element are picked up by the renderer:

omnispec-renderer {
--omnispec-color-primary: #8B5CF6;
--omnispec-color-primary-hover: #7C3AED;
--omnispec-font-sans: 'Inter', sans-serif;
}

See Theming for the full token list.

Sizing the element​

By default the element renders as display: block with width: 100% and height: 100%. Position it within your layout like any other block-level element:

omnispec-renderer {
height: 100vh;
}

Framework integration​

Vanilla HTML​

<script src="https://unpkg.com/@apiboost/omnispec@latest/dist/wc/standalone.js"></script>
<omnispec-renderer spec-url="/openapi.json"></omnispec-renderer>

Vue 3​

Tell the Vue compiler that any <omnispec-...> tag is a custom element so it does not try to resolve it as a Vue component:

// vite.config.ts
import vue from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('omnispec-'),
},
},
})],
})
<script setup lang="ts">
import '@apiboost/omnispec/wc'
import { ref, onMounted } from 'vue'
import type { OmniSpecRendererElement } from '@apiboost/omnispec/wc'

const docs = ref<OmniSpecRendererElement | null>(null)
onMounted(() => {
if (docs.value) docs.value.theme = { base: 'dark' }
})
</script>

<template>
<omnispec-renderer
ref="docs"
spec-url="/openapi.json"
@spec-loaded="console.log($event.detail)"
></omnispec-renderer>
</template>

Angular​

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import '@apiboost/omnispec/wc'

@Component({
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `<omnispec-renderer spec-url="/openapi.json"></omnispec-renderer>`,
})
export class AppComponent {}

Svelte 5​

<script lang="ts">
import '@apiboost/omnispec/wc'
import type { OmniSpecRendererElement } from '@apiboost/omnispec/wc'

let docs: OmniSpecRendererElement | undefined = $state()
$effect(() => {
if (docs) docs.theme = { base: 'dark' }
})
</script>

<omnispec-renderer
bind:this={docs}
spec-url="/openapi.json"
></omnispec-renderer>

React​

If you already use React, prefer the React component — there is no benefit to wrapping it in a custom element. The <omnispec-renderer> element exists for non-React stacks.

Pro features in the Web Component​

Pro

Pro renderers (GraphQL, SOAP/WSDL, gRPC), full white-label theming (theme.overrides), and interactive OAuth require Apiboost OmniSpec Pro. In the free core, the <omnispec-renderer> element renders OpenAPI and AsyncAPI specs with the base light/dark/auto theme and CSS-variable overrides. A parallel Pro Web Component is not shipped today — Pro features are available through the React component.

Limitations and future work​

  • JSON attributes are convenient but verbose. Prefer the imperative property API for production use.
  • @emotion/css style mirroring copies emotion-generated styles from document.head into the shadow root. The footprint per page is tiny (typically a few kilobytes), but if you mount many <omnispec-renderer> elements on one page they will each carry a copy. For most users this is not a concern.