Configuration

Custom scripts

Add custom CSS and JavaScript for analytics, widgets, styling, and third-party integrations on your documentation site.

Use custom CSS and JavaScript to fully customize the look and behavior of your documentation. Every .css and .js file inside your project (the folder that holds velu.json, at any depth) is included on every page. You don't import the files or list them in velu.json.

my-docs
velu.jsonstyle.css
scripts
analytics.js
quickstart.mdx

Style with Tailwind CSS

Use Tailwind CSS utility classes on HTML elements in MDX to control layout, spacing, colors, and other visual properties. Common classes:

  • w-full: full width
  • aspect-video: 16:9 aspect ratio
  • rounded-xl: large rounded corners
  • block, hidden: display control
  • dark:hidden, dark:block: dark-mode visibility (tied to Velu's html[data-theme] toggle)
<img className="w-full rounded-xl" src="/images/diagram.png" alt="" />
<div className="hidden dark:block">Shown only in dark mode</div>

You can combine Tailwind utilities with classes from a custom CSS file on the same element.

Inline styles

For one-off values that aren't covered by a utility, use the style prop, or define a class in a custom CSS file for anything you reuse.

<img style={{ width: '350px', margin: '12px auto' }} src="/images/diagram.png" />

Inline style props apply after the page renders and can cause a small layout shift. Prefer Tailwind utilities or classes from a custom CSS file to avoid shifts or flickering.

Add custom CSS

Create a .css file anywhere in your project. Velu links it from the <head> of every page after its own stylesheet and after the colors and font overrides from velu.json, so your rules win the cascade without !important. Because the link is in the server-rendered HTML there is no flash of unstyled content.

Any class names, ID selectors, or element selectors you define become available across all of your MDX files. For example, define a class in style.css:

.my-callout {
border-radius: 1rem;
background: #f0f9ff;
padding: 1rem;
}

and use it in any page:

<div className="my-callout">This box is styled by style.css.</div>

This box is styled by this site's own style.css: the same auto-include described on this page.

The callouts on this page have a dashed accent border for the same reason: the site's style.css targets them with the callout element selector, scoped to this page with html[data-current-path="/configuration/custom-scripts"]. Both hooks are documented below.

You can also restyle the layout itself. For example, the header and footer:

#navbar {
background: #fffff2;
padding: 1rem;
}
#footer {
margin-top: 2rem;
}

The internal velu- class names (.velu-card, .velu-sidebar__item, …) can change between releases. Use the ID selectors, element selectors, and data attributes below: they are the stable, supported hooks.

Velu exposes two types of CSS targeting hooks:

  • ID selectors: unique page-level elements targeted with #value { } in CSS
  • Element selectors: component and layout elements targeted with value { } in CSS (no # or . prefix)

Use inspect element to find references to elements you're looking to customize.

ID selectors

Each ID appears once per page. Use these as #value in CSS. For example, #navbar { background: red; }.

Page layout
  • #body-content: Outermost wrapper for the page body.
  • #content-area: Primary content area (the <main>), excluding the sidebar and table of contents.
  • #content: Inner content element within the content area: title, description, prose, feedback, pagination.
  • #footer: Page footer. Rendered when footer.links is set in velu.json. Also targetable as an element selector: footer.
  • #pagination: Bottom pagination bar with previous and next page links.
Navigation
  • #navbar: Top navigation bar: brand, search, actions, and the tabs row.
  • #topbar-cta-button: Call-to-action button in the topbar: the navbar.primary button from velu.json (not rendered for the GitHub variant, which is an outlined link).

On small screens the sidebar itself becomes the drawer. Target it with #body-content[data-drawer-open="true"] #sidebar and #sidebar-content.

Sidebar
  • #sidebar: The sidebar navigation panel. On small screens this is also the drawer.
  • #sidebar-content: Scrollable content area within the sidebar.
Table of contents
  • #table-of-contents: Table of contents panel on the right side of the page.
  • #table-of-contents-content: The heading list within the table of contents (also the toc element).
Search
  • #search-bar-entry: Search bar trigger in the topbar (every viewport width).
  • #search-input: Text input field within the search modal.
AI assistant
  • #assistant-entry: AI assistant button in the topbar (published sites with Ask AI enabled).
  • #chat-assistant-sheet: AI assistant chat panel.
  • #chat-assistant-textarea: Text input within the AI assistant panel.
API reference
  • #request-example: Request example panel in the API playground.
  • #response-example: Response example panel in the API playground.
  • #api-playground-input: Input section of the API playground.
  • #endpoints-menu-trigger: Button that opens the endpoint selector dropdown.
Feedback
  • #feedback-thumbs-up: Thumbs-up feedback button at the bottom of a page.
  • #feedback-thumbs-down: Thumbs-down feedback button at the bottom of a page.
  • #feedback-form: Feedback form shown after a thumbs-down response.
  • #feedback-form-input: Text input within the feedback form.
  • #feedback-form-cancel: Cancel button within the feedback form.
  • #feedback-form-submit: Submit button within the feedback form.
Page context menu
  • #page-context-menu: Contextual options menu for the current page (the Copy page button and its dropdown).
  • #page-context-menu-button: Button that triggers the page context menu.
Localization
  • #localization-select-trigger: Button that opens the language selector.
  • #localization-select-content: Dropdown content of the language selector.
  • #localization-select-item: The first language option. To style every option use #localization-select-content [data-component="nav-dropdown-item"].
Changelog
  • #changelog-filters: Filter controls on a changelog page.
  • #changelog-filters-content: Content area within the changelog filter panel.

Element selectors

Multiple instances of these elements can appear on a page. Use these as value in CSS. For example, card { border: 1px solid red; }.

Components whose root has no semantic HTML meaning render as a custom tag with that name (card, callout, code-block, …). Velu's own stylesheet lives in a CSS cascade layer and your custom CSS does not, so a plain card { } (low specificity) still overrides Velu's .velu-card rules without !important.

Where a component's root must stay a real HTML element for accessibility or behavior (a link, a button, a <details> disclosure, a list, a text field, a heading), Velu keeps that tag and marks it with data-component="<name>" instead. Those are listed as [data-component="…"] below; everything else is a plain element selector.

card { border-radius: 0; }
callout { border-left-width: 4px; }
/* Root is a native <details>, so it's an attribute selector */
[data-component="accordion"] { border: 1px solid red; }

Wrapper elements rendered by Velu's layout primitives (sidebar-group, nav-tabs, topbar-right-container, card-group, columns, feedback-toolbar, contextual-feedback-container, chat-assistant-sheet-header) set display and gap inline. Add !important to override those two properties; everything else on them, and all properties on the other elements, override normally.

Content components
  • [data-component="accordion"]: Collapsible accordion item (a <details>).
  • accordion-group: Wrapper grouping multiple accordions.
  • callout: Callout block (Note, Warning, Tip, etc.). The variant is exposed as callout[data-type="warning"].
  • card: Individual card element.
  • card-group: Wrapper grouping multiple cards.
  • columns: Multi-column layout wrapper.
  • code-block: Code block element.
  • code-block-icon: Icon displayed in a code block header or tab.
  • [data-component="code-block-copy-button"]: Copy button shown on a code block. Hide it with [data-component="code-block-copy-button"] { display: none; }.
  • code-group: Tabbed group of code blocks.
  • [data-component="frame"]: <Image chrome="frame"> wrapper.
  • step: Individual step within a steps sequence.
  • steps: Numbered steps container.
  • update: Changelog update entry.
Page layout
  • mdx-content: Rendered MDX content area.
  • eyebrow: Small label displayed above a page title.
  • [data-component="breadcrumb-list"]: Breadcrumb navigation (mobile header; a <button> that opens the drawer).
  • breadcrumb-item: Individual breadcrumb item.
Topbar navigation
  • [data-component="nav-logo"]: Logo link in the navigation bar. To resize the image target [data-component="nav-logo"] img.
  • [data-component="navbar-link"]: Link or button within the navigation bar's actions.
  • [data-component="nav-anchors"]: Container for anchor links (rendered in the sidebar's context zone).
  • [data-component="nav-anchor"]: Individual anchor link.
  • nav-tabs: Tab bar in the top navigation.
  • [data-component="nav-tabs-item"]: Individual tab item in the top navigation tab bar.
  • [data-component="mobile-nav-tabs-item"]: Tab item in the mobile navigation drawer.
  • topbar-right-container: Right section of the topbar.
Topbar dropdown

Products, versions and languages share one dropdown component.

  • [data-component="nav-dropdown-trigger"]: Button that opens a navigation dropdown.
  • [data-component="nav-dropdown-content"]: Content container for a navigation dropdown.
  • [data-component="nav-dropdown-item"]: Individual item within a navigation dropdown.
  • nav-dropdown-item-title: Title text within a dropdown item.
  • nav-dropdown-item-icon: Icon within a dropdown item.
Products selector
  • [data-component="nav-dropdown-products-selector-trigger"]: Button that opens the products selector dropdown.
  • [data-component="nav-dropdown-products-selector-content"]: Content container for the products selector.
  • [data-component="nav-dropdown-products-selector-item"]: Individual product in the selector.
  • [data-component="nav-dropdown-products-selector-item"] nav-dropdown-item-title: Title of a product selector item.
  • [data-component="nav-dropdown-products-selector-item"] nav-dropdown-item-icon: Icon of a product selector item.
Sidebar
  • sidebar-group: Group of related sidebar links (one per navigation group).
  • sidebar-group-icon: Icon for a sidebar group or link.
  • [data-component="sidebar-group-header"]: Header of a collapsible nested group (a <summary>).
  • [data-component="sidebar-title"]: Title heading of a sidebar group.
  • sidebar-nav-group-divider: Divider between the anchors and the page list (rendered when anchors are configured).
Table of contents
  • toc: Table of contents container.
  • toc-item: Individual heading entry in the table of contents.

The table of contents positions its rows and rail with inline styles, so display, padding, color and font-weight on toc-item need !important to override; other properties override normally.

Footer
  • footer: Standard page footer. Also targetable as an ID selector: #footer.
  • advanced-footer: Wrapper around the footer with its link columns.
Pagination
  • [data-component="pagination-prev"]: Previous page link in the pagination bar.
  • [data-component="pagination-next"]: Next page link in the pagination bar.
  • pagination-title: Page title shown in the pagination bar.
API reference
  • api-section: Section of an API endpoint page (Authorizations, Parameters, Body, Response).
  • [data-component="api-section-heading"]: Heading of an API endpoint section.
  • field: Parameter or property field in the API reference.
  • option-dropdown: Dropdown for selecting between API operations in the playground.
  • [data-component="tryit-button"]: "Try it" / "Send" button of the API playground.
  • method-pill: HTTP method badge (GET, POST, etc.) on an endpoint. In the sidebar: #sidebar method-pill.
  • prompt: Prompt component.
AI assistant
  • [data-component="chat-assistant-sheet"]: AI assistant panel container (also #chat-assistant-sheet).
  • chat-assistant-sheet-header: Header of the AI assistant panel.
  • chat-assistant-sheet-content: Content area of the AI assistant panel.
  • [data-component="chat-assistant-input"]: Text input within the AI assistant panel.
  • chat-assistant-floating-input: Floating "Ask a question" input at the bottom of a page.
  • [data-component="chat-assistant-send-button"]: Send button in the panel and the floating input.
  • chat-assistant-disclaimer-text: Hint text displayed below the assistant input.
  • starter-question-text: Suggested starter question shown in an empty assistant panel.
Feedback
  • feedback-toolbar: Toolbar containing page feedback controls.
  • contextual-feedback-container: Container for the page feedback widget.
  • contextual-feedback-form: Feedback form shown after a thumbs-down.
  • [data-component="contextual-feedback-form-title"]: Title of the feedback form.
  • [data-component="contextual-feedback-input"]: Text input within the feedback form.
  • [data-component="contextual-feedback-button"]: Thumbs-up / thumbs-down buttons.
  • [data-component="contextual-feedback-form-submit-button"]: Submit button for the feedback form.
Authentication
  • [data-component="logout-link"]: Log out button shown on private documentation.
404 page
  • not-found-container: Root container of the 404 page.
  • not-found-status-code: Status code display on the 404 page.
  • [data-component="not-found-title"]: Title heading on the 404 page.
  • [data-component="not-found-description"]: Description text on the 404 page.
  • [data-component="not-found-recommended-page-link"]: The "Back to Home" link.
Tree
  • tree: File tree container.
  • [data-component="tree-folder"]: Folder entry within a file tree (a <details>).
  • tree-file: File entry within a file tree.

Data attributes

Some elements expose data attributes you can use as CSS selectors.

Active state (data-active):

  • [data-component="nav-dropdown-item"][data-active]: Active item in a nav dropdown.
  • [data-component="mobile-nav-tabs-item"][data-active]: Active tab in the mobile nav drawer.
  • sidebar-group[data-active]: Sidebar group containing the current page.
  • #sidebar-content li[data-active]: Active sidebar link (the link itself also carries aria-current="page").
  • [data-component="nav-tabs-item"][data-active]: Active top nav tab.
  • toc-item[data-active]: Active table of contents item.
  • toc-item[data-active-deepest]: Velu highlights one heading at a time, so this marks the same item as data-active.

Component name (data-component-name):

  • [data-component-name="theme-toggle"]: The light/dark theme toggle.

Component part (data-component-part): card parts:

  • [data-component-part="card-content-container"]: Inner wrapper around a card's content.
  • [data-component-part="card-icon"]: Icon within a card.
  • [data-component-part="card-title"]: Title text within a card.
  • [data-component-part="card-content"]: Description content within a card.
  • [data-component-part="card-image"]: Image displayed at the top of a card.
  • [data-component-part="card-cta"]: Call-to-action label within a card.

Current path (data-current-path): the <html> element carries the current route, kept in sync on client-side navigation. Use it to scope rules to one page or a whole section:

/* The root page */
html[data-current-path="/"] #table-of-contents {
display: none;
}
/* A specific page */
html[data-current-path="/quickstart"] #navbar {
background: #fffff2;
}
/* Every page under a section */
html[data-current-path^="/api-reference/"] #sidebar {
--accent-color: #0ea5e9;
}

Theme (data-theme), <html> carries data-theme="light" or data-theme="dark". Add dark-mode variants of your rules with it:

callout {
background: #f0f9ff;
}
html[data-theme="dark"] callout {
background: #0c1a2b;
}

Custom JavaScript

Custom JavaScript lets you add executable code globally. It is the equivalent of adding a <script> tag with your code to every page.

Velu includes any .js file inside your project on every page. Scripts run after the page becomes interactive (once the server-rendered HTML has hydrated) so they can read and change the DOM safely. They run once per full page load and do not re-run on client-side navigation; when several files are present they run in path order (a.js, then scripts/b.js).

To load a third-party script, inject a <script> element from your custom JavaScript file instead of adding raw <script> tags in MDX:

const script = document.createElement('script');
script.src = 'https://example.com/widget.js';
script.async = true;
document.head.appendChild(script);

For example, add the following ga.js file to enable Google Analytics across your entire site:

window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'TAG_ID');

If custom JavaScript is included on this site, this sentence is replaced after the page loads.

Files are plain classic scripts, not ES modules: top-level function and var declarations become globals, so snippets like the one above work unchanged.

Custom scripts run with full access to the page. Only include code you trust, and never put API keys, tokens, or other secrets in them: every visitor can read them.

Was this page helpful?