React Router
This library requires React 19+
There are four steps to installation:
- Install the npm packages
- Import the CSS
- Configure fonts
- Configure theme provider
This guide assumes you've already installed React and React Router in framework mode (v7 and up). If not, run this command and follow the prompts to create your project:
npm create react-router@latest1. Install the npm packages
pnpm add @qualcomm-ui/react @qualcomm-ui/react-core @qualcomm-ui/core @qualcomm-ui/qds-core @qualcomm-ui/dom @qualcomm-ui/utils @qualcomm-ui/react-router-utils @tanstack/react-virtual lucide-react
npm i @qualcomm-ui/react @qualcomm-ui/react-core @qualcomm-ui/core @qualcomm-ui/qds-core @qualcomm-ui/dom @qualcomm-ui/utils @qualcomm-ui/react-router-utils @tanstack/react-virtual lucide-react
yarn add @qualcomm-ui/react @qualcomm-ui/react-core @qualcomm-ui/core @qualcomm-ui/qds-core @qualcomm-ui/dom @qualcomm-ui/utils @qualcomm-ui/react-router-utils @tanstack/react-virtual lucide-react
2. Import the CSS
In your global CSS file (default app/app.css), import the QUI styles.
@import "@qualcomm-ui/qds-core/styles/components.css";
@import "@qualcomm-ui/qds-core/themes/qualcomm-dark.css";
@import "@qualcomm-ui/qds-core/themes/qualcomm-light.css";@import "tailwindcss";
/* Recommended: install and import @qualcomm-ui/tailwind-plugin */
@import "@qualcomm-ui/tailwind-plugin/qui-strict.css";
/* Important: always order these imports after the tailwindcss import */
@import "@qualcomm-ui/qds-core/styles/components.css" layer(components);
@import "@qualcomm-ui/qds-core/themes/qualcomm-light.css" layer(components);
@import "@qualcomm-ui/qds-core/themes/qualcomm-dark.css" layer(components);Multi Theme
If you only intend to support a single theme, you may omit the other import.
Learn more about the available brands in the theme documentation.
3. Configure fonts
QUI components are designed with the Roboto Flex and Roboto Mono font families.
Add the links to your application's <head> element:
// root.tsx
<html lang="en">
<head>
{/* ... */}
<link href="https://fonts.googleapis.com" rel="preconnect" />
<link href="https://fonts.gstatic.com" rel="preconnect" />
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wdth,wght@8..144,25..151,400..600&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400..500&display=swap"
rel="stylesheet"
/>
</head>
<body>{/* ... */}</body>
</html>4. Configure theme provider
QUI components support both light and dark modes. Choose one of the following approaches for your site:
- Single theme (static): lock to one theme
- Theme switching (dynamic): support both light and dark modes and persist the user's choice to browser storage
Single theme (static)
If you only intend to support one theme, apply the theme attribute to your app's root element:
<html data-theme="dark" data-brand="qualcomm" style={{colorScheme: "dark"}}>
{/* ... */}
</html>Continue to next steps
Theme switching (dynamic)
Follow this step to configure a cookie for theme switching. The user's preferred theme will be restored when they return to the site.
Create the cookie
// app/sessions.server.ts
import {createCookie} from "react-router"
export const qdsThemeCookie = createCookie("app-qds-theme", {
// one year
maxAge: 31536000,
})Update the root component
First we'll read the cookie. Create a loader function:
import {type LoaderFunctionArgs, useLoaderData} from "react-router"
import {
isTheme,
PreventFlashOnWrongTheme,
Theme,
ThemeProvider,
useTheme,
} from "@qualcomm-ui/react-router-utils/client"
import {type QdsThemeContextValue} from "@qualcomm-ui/react/qds-theme"
import {qdsThemeCookie} from "./sessions.server"
interface RootLoaderData {
qdsTheme: Theme
}
export async function loader({
request,
}: LoaderFunctionArgs): Promise<RootLoaderData> {
const cookie = request.headers.get("cookie")
const qdsTheme = await qdsThemeCookie.parse(cookie)
return {
// add fallback if data from cookie is malformed
qdsTheme: isTheme(qdsTheme) ? qdsTheme : Theme.DARK,
}
}
// ...Then we'll read the data and set up the theme provider:
import {useRouteLoaderData} from "react-router"
export function Layout({children}: {children: ReactNode}) {
const data = useRouteLoaderData<RootLoaderData>("root")
return (
<ThemeProvider theme={data?.qdsTheme} themeAction="/action/set-theme">
{children}
</ThemeProvider>
)
}
export default function App({children}) {
const {qdsTheme: ssrTheme} = useLoaderData<RootLoaderData>()
const [theme] = useTheme()
return (
<html
data-brand="qualcomm" // or snapdragon, or dragonwing
data-theme={theme}
lang="en"
style={{colorScheme: theme || "dark"}}
>
<head>
{/* If the cookie is empty, this component injects an inline script
to apply the user's system theme before hydration */}
<PreventFlashOnWrongTheme ssrTheme={Boolean(ssrTheme)} />
</head>
<body>{children}</body>
</html>
)
}Next, we'll set up the server action that stores theme changes:
// app/routes/action.set-theme.ts
import type {ActionFunction} from "react-router"
import {createThemeAction} from "@qualcomm-ui/react-router-utils/client"
import {qdsThemeCookie} from "../sessions.server"
export const action: ActionFunction = createThemeAction(qdsThemeCookie)(Optional) create a component that toggles between themes:
import {
type MouseEvent,
type ReactNode,
useCallback,
useEffect,
useRef,
} from "react"
import {MoonIcon, SunIcon} from "lucide-react"
import {IconButton} from "@qualcomm-ui/react/button"
import {Theme, useTheme} from "@qualcomm-ui/react-router-utils/client"
export function ThemeToggle(): ReactNode {
const [theme, setTheme] = useTheme()
const handleThemeSwitch = () => {
const nextTheme = theme === Theme.DARK ? Theme.LIGHT : Theme.DARK
setTheme(nextTheme)
}
return (
<IconButton
aria-label="Toggle Theme"
icon={theme === Theme.LIGHT ? SunIcon : MoonIcon}
onClick={handleThemeSwitch}
size="sm"
variant="ghost"
/>
)
}Your application is now ready to import and use our components.
Next Steps
- Learn more about theming in our theming documentation.
- Use the navigation menu on the left to view component documentation and examples.
Troubleshooting
Styles aren't loading
If @qualcomm-ui/react components are appearing without styles, check the following:
- Ensure that you've imported the CSS from step 2.
- Verify that you've configured the theme provider from step 4.
If styles still aren't appearing, inspect the DOM of your application in your browser's dev tools. Your application's <html> element should have at least two attributes:
data-brand: the QDS brand (eitherqualcomm,snapdragon, ordragonwing)data-theme: the QDS theme (eitherlightordark)
Your <html> element should look something like this:
<html
data-brand="qualcomm"
data-theme="light"
style="color-scheme: light"
></html>Note that you need to import the corresponding CSS for the brand you've selected:
@import "@qualcomm-ui/qds-core/themes/qualcomm-dark.css";
@import "@qualcomm-ui/qds-core/themes/qualcomm-light.css";@import "@qualcomm-ui/qds-core/themes/snapdragon-dark.css";
@import "@qualcomm-ui/qds-core/themes/snapdragon-light.css";@import "@qualcomm-ui/qds-core/themes/dragonwing-dark.css";
@import "@qualcomm-ui/qds-core/themes/dragonwing-light.css";Component Styles
Always import component styles, regardless of the chosen brand.
@import "@qualcomm-ui/qds-core/styles/components.css";Migrating from legacy QUI
NextGen is independent of the legacy @qui/react package. Both can be installed and used in the same project without conflicts.
/* this is fine */
@import "@qui/styles/dist/all.min.css";
@import "@qui/base/dist/all.min.css";
@import "@qualcomm-ui/qds-core/styles/components.css";
@import "@qualcomm-ui/qds-core/themes/qualcomm-dark.css";
@import "@qualcomm-ui/qds-core/themes/qualcomm-light.css";NOTE
We're working on a codemod script to automate the migration process. Check back regularly for updates!