component — brand
Logo
The quebi wordmark or the round q, in the right ink for the theme — ink on Daylight, light on Cinematic — switched by CSS so a prerendered page never flashes the wrong one. Pass srcInk/srcLight to point at your own hosted copies.
- brand
- logo
- wordmark
- mark
- theme
- image
use a logo when
- The wordmark at the left of a nav bar (height 20, or 32 on a landing page) and in a footer.
- The mark (the round q) where the name is already said nearby, at 36px or more.
don't
- Don't recolour, outline, stretch or add effects to it — it ships in exactly two inks.
- Don't retype the wordmark in Outfit; it is a drawing, not text.
- Don't crowd it: keep clear space of at least the height of the q around it.
- Don't use it as a page watermark. The giant mark behind a stage is the Stage's own glyph.
03 examples
Wordmark
The default: 20px for a nav bar, 32px in a landing page's top-left corner.
Mark
The round q on its own, at 36px or more — where the name is already said nearby.


Both inks
Each logo renders both files and the theme picks one. A `light` or `dark` class on any ancestor re-themes the subtree, so the same component reads on paper and on ink.
what to use instead
by jobBy what the logo was doing.
- A decorative mark behind a headline
- Stage — Its `glyph` draws the mark in the glyph ink, hidden from assistive tech.
source
logo.tsxCopy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.
import { cn } from "@/lib/utils"
/**
* Logo — quebi design system
*
* The quebi wordmark, or the round q on its own, in the right ink for the
* theme: ink on Daylight, light on Cinematic.
*
* Both files are rendered and the theme picks one with CSS, rather than the
* component reading the theme and choosing a `src`. The site is prerendered
* with no theme known at build time, so a choice made in React would bake one
* ink into the HTML and swap it after hydration — a flash of the wrong logo on
* every dark page load. The selectors follow the `.dark` class the theme sets
* on `<html>`, and a `.light` subtree inside a dark page wins back the ink one.
*
* Keep clear space of at least the height of the q around it. Never recolour,
* outline, stretch or add effects to it, and never retype the wordmark in
* Outfit — it is a drawing, not text.
*/
/** Intrinsic aspect ratios of the shipped files, so the width is reserved before they load. */
const ASPECT = { wordmark: 762 / 240, mark: 1 } as const
const DEFAULT_HEIGHT = { wordmark: 20, mark: 36 } as const
const DEFAULT_SRC = {
wordmark: { ink: "/brand/quebi-wordmark-ink.png", light: "/brand/quebi-wordmark-light.png" },
mark: { ink: "/brand/quebi-mark-ink.png", light: "/brand/quebi-mark-light.png" },
} as const
export interface LogoProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
/** `wordmark` (default) for navigation and footers; `mark`, the round q, where the name is already said. */
variant?: "wordmark" | "mark"
/**
* Rendered height in px. Defaults to 20 for the wordmark (a nav bar) and 36
* for the mark; 32 suits a landing page's top-left nav. Keep the mark at 36
* or more.
*/
height?: number
/** Your own hosted copy of the ink (dark-on-light) file. */
srcInk?: string
/** Your own hosted copy of the light (light-on-dark) file. */
srcLight?: string
/** Accessible name. Defaults to "quebi". */
label?: string
}
export function Logo({
variant = "wordmark",
height = DEFAULT_HEIGHT[variant],
srcInk = DEFAULT_SRC[variant].ink,
srcLight = DEFAULT_SRC[variant].light,
label = "quebi",
className,
...props
}: LogoProps) {
const width = Math.round(height * ASPECT[variant])
return (
<span
data-slot="logo"
data-variant={variant}
role="img"
aria-label={label}
className={cn("inline-block shrink-0 leading-none", className)}
{...props}
>
<img
data-ink="ink"
src={srcInk}
alt=""
width={width}
height={height}
draggable={false}
className="block max-w-none [.dark_&]:hidden [.dark_.light_&]:block"
/>
<img
data-ink="light"
src={srcLight}
alt=""
width={width}
height={height}
draggable={false}
className="hidden max-w-none [.dark_&]:block [.dark_.light_&]:hidden"
/>
</span>
)
}