QUI React

Vite / Webpack / etc.

TIP

We recommend starting with our preconfigured Vite template. Otherwise, follow the steps below for manual installation.

Root Provider

This library exports a QuiRoot component which provides context for global notifications and alerts. It should wrap your component tree.

import {ReactNode} from "@qui/react"
import {QuiRoot} from "@qui/react"
export function App(): ReactNode {
return <QuiRoot>{/* The rest of your app */}</QuiRoot>
}

Fonts

Fonts are sourced from Google. Add the links to your application's <head> element:

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wdth,wght@8..144,110,400;8..144,110,560;8..144,114,400;8..144,114,500;8..144,114,520;8..144,114,660;8..144,114,680&family=Roboto+Mono&display=swap"
rel="stylesheet"
/>

Theme

All components ship with dark and light variants.

TIP

The @qui/styles package applies CSS variables based on the presence of a dark or light className on the nearest ancestor element. To manage this, we'll use hooks and context.

import {
createContext,
useCallback,
useContext,
Dispatch,
SetStateAction,
ReactNode,
} from "react"
import {QuiTheme} from "@qui/base"
// this will be used to store the theme in localStorage.
export const appThemeKey = "my-qui-app-theme-key"
export interface ThemeState {
mode: QuiTheme
setMode: Dispatch<SetStateAction<QuiTheme>>
toggleMode: () => void
}
const ThemeContext = createContext<ThemeState | null>(null)
interface Props {
children: ReactNode
}
export function ThemeProvider({children}: Props) {
const [mode, setMode] = useState<QuiTheme>(
localStorage.getItem(appThemeKey) === "light" ? "light" : "dark",
)
const html = document.getElementById("html")
if (html && !html.className.includes(mode)) {
html.className = mode
}
const toggleMode = useCallback(() => {
const html = document.getElementById("html")
if (!html) {
console.warn("Error, expecting HTML element but it was not found")
return
}
setMode((prevState) => {
const nextState = prevState === "dark" ? "light" : "dark"
html.classList.remove(prevState)
html.classList.add(nextState)
localStorage.setItem(appThemeKey, nextState)
return nextState
})
}, [])
const context: ThemeState = useMemo(
() => ({mode, setMode, toggleMode}),
[mode, setMode, toggleMode],
)
return (
<ThemeContext.Provider value={context}>{children}</ThemeContext.Provider>
)
}
/* Optional: export a helper hook. */
export function useTheme() {
const themeContext = useContext(ThemeContext)
if (!themeContext) {
throw new Error(
"All calls to useTheme can only be performed from a child of a <ThemeProvider>",
)
}
return themeContext
}

Next, wrap your application in the theme provider:

import {createRoot} from "react-dom/client"
import {ThemeProvider} from "./theme-provider"
import App from "./App"
import "./index.css"
createRoot(document.getElementById("root")!).render(
<ThemeProvider>
<App />
</ThemeProvider>,
)

Import Styles

Add the following imports to your project's App root or global CSS.

import "@qui/styles/dist/all.min.css"
import "@qui/base/dist/all.min.css"

Setup Complete

Now you're ready to start importing and using our components. Continue on to our Component Documentation.