Mantle
Mantle is ngrok's UI library and design system that powers its front-end.
Overview
Mantle is a carefully designed system of React components and utilities that establishes a unified design language and consistent user experience across ngrok's web applications. Built with flexibility, extensibility, and developer ergonomics in mind, Mantle prioritizes accessibility, performance, and long-term maintainability. Developed in TypeScript, it offers strong typing, rich IDE support, and increased confidence through compile-time safety. By progressively enhancing standard DOM elements, it not only improves usability and accessibility, but also fills functional gaps. The result is a stable foundation for building cohesive, modern UIs throughout the platform.
To learn more about the design principles and architectural decisions that guide Mantle, see the Philosophy page.
All of Mantle's components are styled using Tailwind. and we compose around the following unstyled primitive component libraries:
Mantle uses Phosphor Icons as the primary icon library, a versatile
and consistent set of icons. In addition, custom-designed icons tailored to ngrok's
needs are available through the @ngrok/mantle/icons module.
Status
Mantle is a living design system and the standard UI library for all ngrok user interfaces. It is continuously evolving as new components, patterns, and improvements are added.
Mantle is available on NPM and is open source on GitHub.
Setup
Installation
Install @ngrok/mantle and all required peerDependencies:
install required mantle peerDependencies
Install tailwindcss as a dev dependency (all frameworks):
Stylesheet
Create one CSS entry file, app.css, and import both mantle stylesheets from it. Each framework
section below says where the file lives.
mantle.css imports Tailwind and the theme tokens for both themes. source-all.css holds one
@source directive that points Tailwind at mantle's dist/ directory. Tailwind 4 skips
node_modules when it scans for class names, so without that directive it generates none of the
classes mantle's components use. The components then render without their styles: an open
Dialog, for example, shows its content in the page flow with no backdrop.
Add your own @source directives to the same file when you keep components in a workspace
package that Tailwind's automatic detection can't see.
In production, source-all.css makes Tailwind scan every file in mantle's dist/, so the
stylesheet carries the utilities of every mantle component, whether your app renders it or not. On
an app that renders Badge alone, that's 181 KB of CSS where 71 KB would do. If you build with
Vite, add mantleSourcesPlugin from
@ngrok/mantle-vite-plugins to vite.config.ts to ship only the classes your bundle uses. The CSS
above stays as it is.
React Router
Install the additional dev dependencies for the Tailwind Vite plugin:
Add the @tailwindcss/vite plugin to your Vite configuration:
In your app's app/root.tsx, import app.css (created in Stylesheet, here at
app/app.css) and set up the Theme Provider,
Toaster, and Tooltip Provider.
You are now ready to use mantle components in your application! Start with the
Button. To let users change the theme, add the ready-made
ThemeSwitcher to your header.
SSR theme cookie (optional)
For apps behind authentication where responses are not publicly cached by a CDN, pass the
theme cookie to useInitialHtmlThemeProps to eliminate the hydration mismatch entirely.
The server then renders the correct theme class, so React hydration matches the inline
script without needing suppressHydrationWarning.
Vite
Install the additional dev dependencies for the Tailwind Vite plugin:
Add the @tailwindcss/vite plugin to your Vite configuration:
In your app's src/main.tsx, import app.css and set up the
Theme Provider, Toaster, and
Tooltip Provider:
To prevent a flash of unstyled content (FOUC), add the theme script to the <head> of your
index.html. The <script> below holds the output of preventWrongThemeFlashScriptContent()
from @ngrok/mantle/theme, generated from the version of mantle this page was built with.
Generate it again after you upgrade mantle. For a <head> that a server writes without React,
see Non-React head on the Theme page.
You are now ready to use mantle components in your application! Start with the
Button. To let users change the theme, add the ready-made
ThemeSwitcher to your header.
Next.js
React SPA
In your app's entry/root file, import app.css and set up the
Theme Provider, Toaster, and
Tooltip Provider:
To prevent a flash of unstyled content (FOUC), add the theme script to the <head> of your
index.html. The <script> below holds the output of preventWrongThemeFlashScriptContent()
from @ngrok/mantle/theme, generated from the version of mantle this page was built with.
Generate it again after you upgrade mantle. For a <head> that a server writes without React,
see Non-React head on the Theme page.
You are now ready to use mantle components in your application! Start with the
Button. To let users change the theme, add the ready-made
ThemeSwitcher to your header.