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
React
Codecomponents/react/logo-demo.tsx
import {LOGO_ASPECT, LOGO_SIZE_PX, Header, HeaderActions, HeaderLogo, Logo} from '@stroeer-labs/design-library/react';
// Every row answers one question a consumer actually has: how big, what colour, what about an exact box, what
// about a11y. Captions carry the numbers because the point is that the width is derived — and they are computed
// from the shared ladder, since hand-typed ones would be the first thing to go stale.
const sizes = (['sm', 'md', 'lg', 'xl'] as const).map((size) => ({
size,
caption: `${size} · ${LOGO_SIZE_PX[size]}px${size === 'md' ? ' (default)' : ''}`,
}));
const colours = [
{className: 'text-foreground', caption: 'inherits — the default'},
{className: 'text-muted-foreground', caption: 'text-muted-foreground · de-emphasised (light)'},
];
export function LogoDemo() {
return (
<div className="space-y-6">
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">Sizes — height is set, width follows the artwork</p>
<div className="flex flex-wrap items-end gap-6">
{sizes.map(({size, caption}) => (
<div key={size} className="space-y-1.5">
<Logo size={size} />
<p className="font-mono text-xs tabular-nums text-muted-foreground">{caption}</p>
</div>
))}
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">
Colour — the mark paints with <code className="font-mono">currentColor</code>
</p>
<div className="flex flex-wrap items-end gap-6">
{colours.map(({className, caption}) => (
<div key={className} className="space-y-1.5">
<Logo className={className} />
<p className="font-mono text-xs text-muted-foreground">{caption}</p>
</div>
))}
</div>
<div className="flex flex-wrap items-end gap-4 pt-1">
<div className="space-y-1.5">
<div className="flex w-fit items-center rounded-lg bg-brand-fixed p-4">
<Logo className="text-brand-fixed-foreground" />
</div>
<p className="font-mono text-xs text-muted-foreground">✓ brand-fixed-foreground on bg-brand-fixed</p>
</div>
{/* `brand-fixed` is navy in BOTH themes (fixed identity, no `.dark` override), so this tile
pins a light surface instead of following the theme — otherwise the dark render is a
1.22:1 smudge, and the demo would be teaching the "Never" case as a specimen. */}
<div className="space-y-1.5">
<div className="flex w-fit items-center rounded-lg bg-brand-fixed-foreground p-4 ring-1 ring-border">
<Logo className="text-brand-fixed" />
</div>
<p className="font-mono text-xs text-muted-foreground">✓ brand-fixed on a light surface</p>
</div>
<div className="space-y-1.5">
<div className="flex w-fit items-center rounded-lg bg-brand-fixed p-4 ring-2 ring-destructive">
<Logo className="text-brand-fixed" />
</div>
<p className="font-mono text-xs text-destructive">✗ brand-fixed on a dark surface — 1.2:1</p>
</div>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">An exact box, when a layout needs one</p>
<div className="flex flex-wrap items-end gap-6">
<div className="space-y-1.5">
<Logo height={28} />
<p className="font-mono text-xs tabular-nums text-muted-foreground">height=28 → {Math.round(28 * LOGO_ASPECT)}×28</p>
</div>
<div className="space-y-1.5">
{/* Outlined, not filled: a tinted slab behind the mark reads as a backing plate, which is
exactly the treatment the mark must never get. */}
<div className="w-fit rounded-md outline-1 outline-dashed outline-border">
<Logo width={160} height={64} />
</div>
<p className="font-mono text-xs tabular-nums text-muted-foreground">
your 160×64 box · mark fits to 160×{Math.round(160 / LOGO_ASPECT)}, centred
</p>
</div>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">
Accessibility — named on its own, <code className="font-mono">decorative</code> beside a product name
</p>
<div className="flex flex-wrap items-end gap-6">
<div className="space-y-1.5">
<Logo size="sm" />
<p className="font-mono text-xs text-muted-foreground">role=img · aria-label="Ströer"</p>
</div>
<div className="space-y-1.5">
<span className="flex items-baseline gap-2">
<Logo size="sm" decorative />
<span className="text-sm text-muted-foreground">design library</span>
</span>
<p className="font-mono text-xs text-muted-foreground">decorative · aria-hidden</p>
</div>
</div>
</div>
<div className="space-y-2">
<p className="text-xs font-medium text-muted-foreground">
In a header — <code className="font-mono">HeaderLogo</code> is the slot, the mark goes inside it
</p>
<Header className="static rounded-lg border">
<HeaderLogo>
<Logo size="sm" />
</HeaderLogo>
<HeaderActions>
<span className="text-xs text-muted-foreground">actions</span>
</HeaderActions>
</Header>
</div>
</div>
);
}Angular
Codecomponents/angular/logo-demo.ts
import {Component} from '@angular/core';
import {LOGO_ASPECT, LOGO_SIZE_PX, HeaderImports, LogoImports} from '@stroeer-labs/design-library/angular';
// Mirrors react/logo-demo.tsx row for row, captions included — this pair is also the parity check for the two
// implementations, and a caption that differs would hide a box that differs.
@Component({
selector: 'dl-logo-demo',
standalone: true,
imports: [LogoImports, HeaderImports],
template: `
<div class="space-y-6">
<div class="space-y-2">
<p class="text-xs font-medium text-muted-foreground">Sizes — height is set, width follows the artwork</p>
<div class="flex flex-wrap items-end gap-6">
@for (item of sizes; track item.size) {
<div class="space-y-1.5">
<dl-logo [size]="item.size" />
<p class="font-mono text-xs tabular-nums text-muted-foreground">{{ item.caption }}</p>
</div>
}
</div>
</div>
<div class="space-y-2">
<p class="text-xs font-medium text-muted-foreground">
Colour — the mark paints with <code class="font-mono">currentColor</code>
</p>
<div class="flex flex-wrap items-end gap-6">
<!-- Static classes on purpose: a dynamic [class] on the host is the one pattern classes()
warns about, since it reconciles the host's static class attribute. -->
<div class="space-y-1.5">
<dl-logo class="text-foreground" />
<p class="font-mono text-xs text-muted-foreground">inherits — the default</p>
</div>
<div class="space-y-1.5">
<dl-logo class="text-muted-foreground" />
<p class="font-mono text-xs text-muted-foreground">text-muted-foreground · de-emphasised (light)</p>
</div>
</div>
<div class="flex flex-wrap items-end gap-4 pt-1">
<div class="space-y-1.5">
<div class="flex w-fit items-center rounded-lg bg-brand-fixed p-4">
<dl-logo class="text-brand-fixed-foreground" />
</div>
<p class="font-mono text-xs text-muted-foreground">✓ brand-fixed-foreground on bg-brand-fixed</p>
</div>
<!-- brand-fixed is navy in BOTH themes (fixed identity, no .dark override), so this tile pins
a light surface instead of following the theme — otherwise the dark render is a 1.22:1
smudge and the demo would teach the "Never" case as a specimen. -->
<div class="space-y-1.5">
<div class="flex w-fit items-center rounded-lg bg-brand-fixed-foreground p-4 ring-1 ring-border">
<dl-logo class="text-brand-fixed" />
</div>
<p class="font-mono text-xs text-muted-foreground">✓ brand-fixed on a light surface</p>
</div>
<div class="space-y-1.5">
<div class="flex w-fit items-center rounded-lg bg-brand-fixed p-4 ring-2 ring-destructive">
<dl-logo class="text-brand-fixed" />
</div>
<p class="font-mono text-xs text-destructive">✗ brand-fixed on a dark surface — 1.2:1</p>
</div>
</div>
</div>
<div class="space-y-2">
<p class="text-xs font-medium text-muted-foreground">An exact box, when a layout needs one</p>
<div class="flex flex-wrap items-end gap-6">
<div class="space-y-1.5">
<dl-logo [height]="28" />
<p class="font-mono text-xs tabular-nums text-muted-foreground">height=28 → {{ presetHeight }}×28</p>
</div>
<div class="space-y-1.5">
<!-- Outlined, not filled: a tinted slab behind the mark reads as a backing plate, which is
exactly the treatment the mark must never get. -->
<div class="w-fit rounded-md outline-1 outline-dashed outline-border">
<dl-logo [width]="160" [height]="64" />
</div>
<p class="font-mono text-xs tabular-nums text-muted-foreground">
your 160×64 box · mark fits to 160×{{ letterboxHeight }}, centred
</p>
</div>
</div>
</div>
<div class="space-y-2">
<p class="text-xs font-medium text-muted-foreground">
Accessibility — named on its own, <code class="font-mono">decorative</code> beside a product name
</p>
<div class="flex flex-wrap items-end gap-6">
<div class="space-y-1.5">
<dl-logo size="sm" />
<p class="font-mono text-xs text-muted-foreground">role=img · aria-label="Ströer"</p>
</div>
<div class="space-y-1.5">
<span class="flex items-baseline gap-2">
<dl-logo size="sm" decorative />
<span class="text-sm text-muted-foreground">design library</span>
</span>
<p class="font-mono text-xs text-muted-foreground">decorative · aria-hidden</p>
</div>
</div>
</div>
<div class="space-y-2">
<p class="text-xs font-medium text-muted-foreground">
In a header — <code class="font-mono">dl-header-logo</code> is the slot, the mark goes inside it
</p>
<dl-header class="static rounded-lg border">
<dl-header-logo>
<dl-logo size="sm" />
</dl-header-logo>
<dl-header-actions>
<span class="text-xs text-muted-foreground">actions</span>
</dl-header-actions>
</dl-header>
</div>
</div>
`,
})
export class LogoDemoComponent {
protected readonly sizes = (['sm', 'md', 'lg', 'xl'] as const).map((size) => ({
size,
caption: `${size} · ${LOGO_SIZE_PX[size]}px${size === 'md' ? ' (default)' : ''}`,
}));
protected readonly letterboxHeight = Math.round(160 / LOGO_ASPECT);
protected readonly presetHeight = Math.round(28 * LOGO_ASPECT);
}