npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@drkaachen/design-system-ui

v1.2.1

Published

DRK shared UI design system for Next.js projects

Downloads

475

Readme

DRK Frontend Monorepo

Monorepo for DRK frontend packages with strict separation between UI, CMS adapters, and runtime helpers.

Package Architecture

@drkaachen/design-system-ui (repo root)

UI-only package with:

  • React components (Header, Footer, Navigation, Button, Modal, Alert, form controls, CookieBanner, Spinner, DrkLogo)
  • SCSS tokens, mixins, globals (including dark mode and reduced-motion support)
  • Cookie consent helpers with DSGVO enforcement utilities
  • HTML sanitizer, scroll-lock utility, and CSP security headers helper

This package intentionally does not include:

  • Sanity client
  • GROQ queries
  • Hostname middleware

@drkaachen/content-sanity (packages/content-sanity)

Optional Sanity adapter package:

  • Sanity client and image URL builder (urlFor)
  • GROQ queries
  • getSiteByHostname

@drkaachen/next-site-runtime (packages/next-site-runtime)

Optional Next.js runtime package:

  • Middleware for hostname-to-site header propagation
  • Runtime helpers for reading site headers
  • Proxy trust and hostname allowlist configuration

Why We Split It

  • Keeps app templates clean and lightweight by default
  • Avoids forced CMS dependencies in UI-only apps
  • Reduces security/privacy surface when CMS is not needed
  • Better GDPR/DSGVO risk control by enabling integrations explicitly per app

Install in Consuming Apps

1) UI-only baseline (recommended default)

npm install @drkaachen/design-system-ui

2) Add Sanity only if required

npm install @drkaachen/content-sanity @drkaachen/next-site-runtime

UI Package Usage (@drkaachen/design-system-ui)

Import globals once in your root layout:

import '@drkaachen/design-system-ui/styles/globals.scss'

Use UI components from package root:

import {
  Header,
  Footer,
  CookieBanner,
  Button,
  Modal,
  Alert,
  Input,
  Label,
  DrkLogo,
  type SiteConfig,
} from '@drkaachen/design-system-ui'

DRK Logo

The DrkLogo component renders the official DRK circular emblem (red cross with "DEUTSCHES ROTES KREUZ" text around the perimeter). It is used automatically in the Header when no custom logoUrl is provided and can also be used standalone:

<DrkLogo size={42} />

Setup: Copy assets/drk-logo.png from this package to your app's public/ directory:

cp node_modules/@drkaachen/design-system-ui/assets/drk-logo.png public/drk-logo.png

The src prop defaults to /drk-logo.png but can be overridden if you place the file elsewhere.

UI SiteConfig is CMS-agnostic and expects a plain logoUrl string:

const site: SiteConfig = {
  _id: 'site-1',
  name: 'DRK Aachen',
  hostname: 'example.de',
  defaultLocale: 'de',
  logoUrl: '/images/logo.svg',
  navigation: [{ label: 'Startseite', href: '/' }],
}

Cookie Consent Enforcement (DSGVO)

The design system provides consent storage and enforcement utilities. Consuming apps must gate non-essential functionality behind consent checks:

import { hasConsent, onConsentChange } from '@drkaachen/design-system-ui'

// Gate analytics behind user consent
if (hasConsent('analytics')) {
  initAnalytics()
}

// Forward consent events to a server-side audit log (DSGVO Art. 7(1))
onConsentChange((consent) => {
  fetch('/api/consent-log', {
    method: 'POST',
    body: JSON.stringify(consent),
  })
})

Available consent utilities:

  • hasConsent(category) — checks if a specific category is consented to
  • hasAllConsent(categories) — checks multiple categories at once
  • clearConsentData() — removes all consent data (Art. 17 right to erasure)
  • getConsentDataForExport() — returns consent in portable JSON (Art. 20 data portability)
  • onConsentChange(callback) — subscribe to consent changes (returns unsubscribe function)

Security Headers

Apply recommended security headers in consuming apps:

// In next.config.ts
import { securityHeaders } from '@drkaachen/design-system-ui/lib/security-headers'

const nextConfig = {
  async headers() {
    return [{ source: '/(.*)', headers: securityHeaders() }]
  },
}

Or in middleware:

import { applySecurityHeaders } from '@drkaachen/design-system-ui/lib/security-headers'

const response = NextResponse.next()
applySecurityHeaders(response.headers, {
  extraImgSrc: ['https://*.sanity.io'],
})

Scroll Lock

iOS-safe body scroll lock for modals and drawers (used internally by Modal and Navigation):

import { lockBodyScroll, unlockBodyScroll } from '@drkaachen/design-system-ui'

Optional Sanity Integration

Get site content via @drkaachen/content-sanity, then map it to UI shape:

import { getSiteByHostname, urlFor } from '@drkaachen/content-sanity'
import type { SiteConfig as UiSiteConfig } from '@drkaachen/design-system-ui'

export async function getUiSite(hostname: string): Promise<UiSiteConfig | null> {
  const cmsSite = await getSiteByHostname(hostname)
  if (!cmsSite) return null

  return {
    _id: cmsSite._id,
    name: cmsSite.name,
    hostname: cmsSite.hostname,
    defaultLocale: cmsSite.defaultLocale,
    logoUrl: cmsSite.logo ? urlFor(cmsSite.logo).height(120).fit('max').auto('format').url() : undefined,
    navigation: cmsSite.navigation,
    footerLinks: cmsSite.footerLinks,
  }
}

If middleware-based site header propagation is needed:

// middleware.ts in consuming app root
export { middleware, config } from '@drkaachen/next-site-runtime/middleware'

Breaking Changes (Hard Cut)

The previous mixed package surface was removed by design.

  • Old package name @drkaachen/design-system -> @drkaachen/design-system-ui
  • Removed from UI package:
    • getSiteByHostname
    • client, urlFor, GROQ query exports
    • middleware export
    • BlockRenderer and LegalPage components
  • New optional packages:
    • @drkaachen/content-sanity
    • @drkaachen/next-site-runtime

Accessibility (WCAG 2.2 AA)

The design system follows WCAG 2.2 Level AA guidelines:

  • Color contrast: Headings use $color-text-accent which maps to $drk-rot (#e60005, ~4.0:1 ratio) — WCAG AA compliant for large text (>=18pt / >=14pt bold, requires 3:1). For small body text that needs red, use $drk-rot-text (#c20004, ~5.2:1 ratio) which meets WCAG AA for all text sizes.
  • Reduced motion: Global prefers-reduced-motion: reduce media query disables all transitions and animations. A @mixin reduced-motion is available for component-level use.
  • Dark mode: Basic prefers-color-scheme: dark support with dark tokens.
  • Focus indicators: Visible 2px red outline with white shadow ring on all interactive elements via @mixin focus-outline.
  • Keyboard navigation: Modal focus trap, Navigation arrow-key/Escape/Home/End support, skip link.
  • Screen readers: Proper ARIA attributes (aria-expanded, aria-haspopup, aria-controls, aria-live, role="alert", role="status").
  • Form accessibility: All form components support aria-describedby for linking to error/hint IDs from Label.

App Template Guidance

For drk-app-template:

  • Keep default dependency set to @drkaachen/design-system-ui only
  • Provide an optional documented module/feature toggle for Sanity setup
  • Only add Sanity env vars and middleware in apps that explicitly enable Sanity

Public Registry Setup

Packages are published publicly to npm. Consuming apps can install without extra registry auth:

npm install @drkaachen/design-system-ui

Optional internal mirror setup (if you later switch to private hosting) is documented in templates/npmrc.consuming-app.private.

Automated Updates in Consuming Apps

Use Dependabot with the template:

  • templates/dependabot.consuming-app.yml

It tracks:

  • @drkaachen/design-system-ui
  • @drkaachen/content-sanity
  • @drkaachen/next-site-runtime

Local Development (Monorepo)

Install dependencies at repository root:

npm install

Run quality checks:

npm run lint          # ESLint (TypeScript, React, jsx-a11y)
npm run format:check  # Prettier formatting check
npm run typecheck     # TypeScript strict mode
npm run typecheck:workspaces
npm run test          # Vitest (128 tests across 8 files)

Run showcase:

cd showcase
npm run dev

Pre-commit Hooks

Husky + lint-staged runs automatically on git commit:

  • *.{ts,tsx} → ESLint fix + Prettier
  • *.{scss,css,json,yml,yaml} → Prettier

Publishing

Publishing runs via GitHub Actions (.github/workflows/publish.yml) and pushes to npm. The publish job requires the npm-publish environment (configure required reviewers in GitHub repo settings).

Requirements before first release:

  • Create an npm organization/user that owns the @drkaachen scope.
  • Add NPM_TOKEN as a repository secret (token with publish rights for that scope).
  • Create a GitHub environment named npm-publish with required reviewers.
  • Bump package versions intentionally before triggering release.

Then trigger the publish workflow manually or via GitHub Release.

Fonts and GDPR/DSGVO

All fonts are self-hosted via @fontsource packages — no external CDN requests at runtime.

| Font | Purpose | Weights | Source | |------|---------|---------|--------| | Open Sans | Body text, UI elements | 300, 400, 500, 700 | @fontsource/open-sans | | Merriweather | Headings | 300, 400, 700 | @fontsource/merriweather |

The body font stack follows the DRK Styleguide:

'Helvetica Neue', 'Open Sans', Helvetica, Arial, sans-serif
  • macOS/iOS users get Helvetica Neue (pre-installed system font)
  • All other users get Open Sans (self-hosted, free, closest visual match to Helvetica Neue per DRK styleguide)
  • Helvetica Neue is a commercial font (Monotype). It is referenced as a system font only — no licensed font files are bundled.
  • No per-project font file copy is required.
  • Do not load fonts from external CDNs.

Cookie Inventory (for Datenschutzerklärung)

| Cookie/Storage | Name | Purpose | Category | Retention | |---------------|------|---------|----------|-----------| | Cookie | drk_cookie_consent_v1 | Stores user's cookie consent preferences | Necessary (TTDSG §25(2)) | 365 days | | localStorage | drk_cookie_consent | Mirrors consent for faster client-side access | Necessary | Until cleared |

Consuming apps must include this information in their Datenschutzerklärung.

Security

See SECURITY.md for vulnerability reporting and disclosure process.

Branch protection is recommended:

  • Require CI to pass before merge
  • Require at least 1 review on pull requests
  • Prevent force-push to main