Logo
The Ströer wordmark. Inline SVG, so it stays sharp at any size and takes its colour from the surrounding text.
Added 14 October 2026
Component, or a file in public/?
Always the component. The mark exists in this repo six times over — three <img src> call sites in
ppv-self-booking, one in national-planner’s navbar, and two apps rendering a PNG, which is why the logo
looks soft there on a HiDPI screen.
An <img> pointing at an SVG is sharp, but it can never take a colour: the file’s own fill wins. Inlining
the SVG is what makes currentColor — and therefore dark mode — possible at all. That is the whole reason
this is a component and not another copied asset.
The artwork, the size ladder and the naming rule live once, in lib/logo.ts, and both framework components
import them.
Colour: inherit by default, brand-fixed on purpose
The mark paints with currentColor, so it follows the text colour of wherever you put it. That is the default
because it is the safe one.
- Inherit (
<Logo />) — inside a footer, a link, a card, anything that already has a sensible text colour. Works in both themes without a second thought. text-brand-fixed dark:text-brand-fixed-foreground— the brand pair, and the right choice on a brand surface such as an app header.--brand-fixedis fixed identity with no.darkoverride, so on its own it renders navy on a dark surface at ~1.2:1 — invisible. Always give it the dark half.text-brand-fixed-foreground— on abg-brand-fixedsurface, i.e. the mark sitting on brand navy.text-muted-foreground— a de-emphasised mark: partner lists, footnotes, “powered by” rows. Light surfaces only: in dark that token is a warm olive (hue 100), which tints the wordmark khaki. Prefertext-foreground/60if you need de-emphasis in both themes.
A logotype is exempt from the WCAG contrast minimums (1.4.3, 1.4.11) and is the sanctioned exception to
1.4.5 Images of Text — which is what licenses this component to be an image of text at all. That is why
text-muted-foreground is allowed here although it sits on the contrast gate’s KNOWN list. Aim for 3:1 anyway;
an unreadable mark is still a bad mark.
Size: a preset, or an exact box
The wordmark’s ratio (~4.53:1) comes from the artwork, so one dimension is always enough.
<Logo size="sm" /> // 20px — headers, dense bars
<Logo size="md" /> // 24px — default
<Logo size="lg" /> // 32px — sign-in, empty states
<Logo size="xl" /> // 40px — print, hero
<Logo height={28} /> // exact height → 127×28
<dl-logo size="sm" />
<dl-logo [height]="28" />
Minimum size: 20px tall (sm), which is why the ladder starts there rather than at 16. The Ö diaeresis
occupies about 3 of the artwork’s 42 viewBox units — roughly 1.1px at 16px tall — so on a 1× display the two
dots merge and the mark reads “Stroer”. Presets also exist so the mark is not 16px in one app and 28px in the
next. Nothing enforces the floor for an explicit width/height; treat 20px as the rule anyway.
Clear space: at least 1× the mark’s height on every side, and nothing but background inside it. The artwork
itself carries almost no padding (1.2 viewBox units ≈ 0.6px at sm), so the space has to come from your layout.
An off-scale height: <Logo className="h-7" /> or <Logo className="h-4 md:h-6" /> — className merges,
so your height replaces the preset’s while w-auto survives and the ratio still resolves. In Angular the class
goes on the host: <dl-logo class="h-7">. This is the better escape hatch, and the responsive one.
width/height are for non-CSS contexts that need the attributes — a PDF header, a fixed-size slot.
Passing either drops the preset, and prefer passing one:
- Both dimensions letterbox inside your box;
preserveAspectRatiois left at its default, so the letters are never stretched. - A px box does not scale with the user’s text size, while the rem-based presets do. Use it only where the surrounding box is fixed too.
- The two frameworks disagree about precedence here, the one place they do: React passes presentation attributes, so a class beats them; Angular applies inline styles, so they beat a class. Do not combine a class with an explicit dimension — pick one mechanism.
Named, or decorative
The logo is an image with a name, so it needs one — unless the name is already there. [a11y]
<Logo /> // role="img" + aria-label
<Logo decorative /> // aria-hidden, silent
<dl-logo />
<dl-logo decorative />
- Named — the mark is the only thing that says whose product this is: a header whose other text is a bare product name (as in the showcase, whose header link reads “Ströer design library”), a sign-in card, an email header.
decorative— the neighbouring text already contains the brand name (“Ströer Core”, “Ströer Self-Booking”), or the mark sits alone in a link that carries its own name. [a11y]label— only if the brand name itself differs in context. It is a proper noun; do not translate it. A blank label is treated asdecorativerather than emitted as an empty name, becauserole="img"with no name is a 1.1.1 failure.role,aria-labelandaria-hiddenare not accepted as props.decorativeandlabelare the only naming levers, on both frameworks. [a11y]
In a link
<a href="/"><Logo /> <span>design library</span></a>
<a href="/" aria-label="Ströer — home"><Logo decorative /></a>
A mark alone in a link with no label leaves the link named only “Ströer” — it identifies the brand but not the
destination (2.4.4). A decorative mark alone in an unlabelled link leaves the link with no accessible
name at all: a 2.4.4 and 4.1.2 failure. [a11y]
In a header
HeaderLogo / dl-header-logo is the slot, not the mark — it only positions what you put inside:
<Header>
<HeaderLogo>
<Logo size="sm" />
</HeaderLogo>
<HeaderActions>…</HeaderActions>
</Header>
<dl-header>
<dl-header-logo>
<dl-logo size="sm" />
</dl-header-logo>
<dl-header-actions>…</dl-header-actions>
</dl-header>
In a lockup with type, align the mark’s box bottom to the text baseline — that is what items-baseline on
the row gives you. Do not add self-center: it cancels the baseline alignment and leaves the mark hanging on
the label’s descender line.
Never
- A copied
stroeer-logo.svgin an app’spublic/, or an<img>pointing at one — that is what this component replaces. - A raster logo. A PNG cannot stay sharp across zoom levels and screen densities.
text-brand-fixedwithout itsdark:half — the token has no dark override, so the mark vanishes.- Recolouring by anything other than a
text-*token: nofill-[#08204a], no inlinestyle. - Hand-written
role/aria-*on the mark — usedecorative/label. [a11y] - Both
widthandheightset “to be safe” — you get letterboxing you did not ask for. Pass one. - Below 20px tall, or with less than 1× clear space.
- A backing plate, gradient or shadow behind the mark; rotating, outlining, cropping or stretching it. If a layout needs that, the layout is wrong.
Open questions
- The artwork is vendored from an app’s
public/folder, not from a brand kit. Now that it ships here it is the de-facto source of truth for every app, so it deserves a check against the official asset — as do the 20px floor and the 1× clear space, which are this library’s reading and not a brand-guide citation. The floor in particular rests on a rasterisation judgement that wants confirming on a real 1× monitor. - The product lockups are missing. “STRÖER | core” (product-access-management-ui) is a two-colour mark, so
currentColorcannot paint it, and it exists only as a PNG today. That app keeps its raster copy until someone supplies an SVG and decides how the second colour is themed — most likely a second component rather than a variant of this one.
Related
/color— the brand tiers, and whybrand-fixeddoes not adapt whilebrand-interactivedoes.- docs/components/header.md — the header slots the mark goes into.