React Router

This library requires React 19+

There are four steps to installation:

  1. Install the npm packages
  2. Import the CSS
  3. Configure fonts
  4. 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@latest

1. Install the npm packages

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

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";

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)

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.

// 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:

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 (either qualcomm, snapdragon, or dragonwing)
  • data-theme: the QDS theme (either light or dark)

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";

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!