No description
  • TypeScript 88.2%
  • HTML 9.6%
  • JavaScript 2.2%
Find a file
2026-08-22 07:52:27 +02:00
src Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
.gitignore Add .gitignore to exclude IDE files, node_modules, build artifacts, and log files 2026-08-22 07:47:49 +02:00
build.mjs Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
CHANGELOG.md Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
index.html Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
LICENSE Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
package-lock.json Add package-lock.json to manage dependencies and ensure consistent installs 2026-08-22 07:52:27 +02:00
package.json Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
README.md Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
standalone.html Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
tsconfig.esm.json Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
tsconfig.json Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00
tsconfig.types.json Add TypeScript configuration and initial implementation for consent manager 2026-08-22 07:47:19 +02:00

tiny-consent v0.6.9

Eine kleine dependency-free Consent-Library in Vanilla JS/TypeScript für Drittanbieter-Ressourcen. v0.6.9 verbindet den manuellen Ansatz mit einem Hybrid-Modus aus Presets, URL-Erkennung, DOM-Hooks, MutationObserver und optionalen automatischen Embed-Placeholdern.

Grundidee

Tiny Consent bietet zwei Betriebsarten:

mode: 'manual'

Der deterministische Modus. Ressourcen werden explizit markiert:

<iframe
  data-consent="youtube"
  data-src="https://www.youtube-nocookie.com/embed/VIDEO_ID"
  hidden>
</iframe>

Die Library kann an beliebiger Stelle geladen werden, solange die zu blockierenden Ressourcen bereits inert markiert wurden.

mode: 'hybrid'

Zusätzlich zum manuellen Markup aktiviert Tiny Consent:

  • eingebaute Presets mit URL-Regeln
  • Erkennung von script[src], iframe[src], link[href] und img[src]
  • Blocking dynamisch eingefügter Ressourcen vor appendChild / insertBefore / replaceChild
  • MutationObserver für spätere DOM-Änderungen
  • Debug-Ausgaben für erkannte, blockierte und unbekannte Drittanbieter

Explizites data-consent hat immer Vorrang vor Auto-Erkennung.

Automatische Embed-Placeholder

Im Hybrid-Modus können automatisch blockierte iframe-Embeds optional direkt durch einen Placeholder ersetzt werden:

createConsentManager({
  version: 1,
  mode: 'hybrid',
  presets: ['youtube', 'vimeo', 'googleMaps'],
  autoPlaceholder: true,
});

Oder konfiguriert:

autoPlaceholder: {
  enabled: true,
  skeleton: true,
  buttonLabel: 'Externen Inhalt laden',
}

Der Placeholder übernimmt nach Möglichkeit das Seitenverhältnis des ursprünglichen iframes und zeigt einen dezenten Skeleton/Shimmer. Der Button gibt nur den betroffenen Service frei. Nach Consent wird das echte Embed eingeblendet; nach einem späteren Widerruf erscheint der Placeholder wieder. prefers-reduced-motion deaktiviert die Animation automatisch.

Scripts, Stylesheets und Bilder bekommen bewusst keinen sichtbaren Auto-Placeholder; die Funktion ist für visuelle Embed-Flächen gedacht.

Placeholder gestalten

Die automatisch erzeugten Placeholder liegen am Platz des Embeds im normalen DOM und lassen sich mit CSS Custom Properties an das Seitendesign anpassen:

:root {
  --tc-placeholder-bg: #f8fafc;
  --tc-placeholder-surface: #ffffff;
  --tc-placeholder-text: #334155;
  --tc-placeholder-muted: #64748b;
  --tc-placeholder-border: #e2e8f0;
  --tc-placeholder-accent: #6d8098;
  --tc-placeholder-accent-hover: #5f7188;
}

Manuell definierte Placeholder via data-consent-placeholder="service" bleiben unverändert möglich.

Wichtig: Grenze des Auto-Modus

Bei dynamisch per JavaScript eingefügten Ressourcen kann Tiny Consent bekannte Ressourcen vor dem Einfügen in den DOM blockieren.

Bei statischem HTML, das der Browser-Parser verarbeitet, kann ein normaler Runtime-Consent-Manager jedoch nicht garantieren, dass ein Request noch nicht durch Parser/Preload-Scanner angestoßen wurde, bevor eine nachträgliche DOM-Erkennung greift. Deshalb gilt:

  • maximale Sicherheit: Manual-Tagging (data-consent + data-src / data-href)
  • maximaler Komfort: Hybrid-Modus möglichst früh im <head> + Presets
  • unbekannte Drittanbieter werden im Hybrid-Modus standardmäßig nicht blockiert

Tiny Consent verspricht daher bewusst kein magisches 100%-Blocking beliebigen statischen Fremdcodes.

Installation

npm install
npm run dev

Build:

npm run build

Erzeugt:

dist/
├── esm/
├── types/
└── tiny-consent.standalone.js

Standalone / Hybrid möglichst früh laden

<head>
  <script>
    window.tinyConsentConfig = {
      version: 1,
      mode: 'hybrid',
      debug: true,
      presets: ['youtube', 'googleMaps', 'googleFonts', 'vimeo', 'ga4']
    };
  </script>

  <script src="/tiny-consent.standalone.js"></script>
</head>

Der Standalone-Bootstrap ruft init() sofort auf. Die UI wartet intern auf document.body, während der Hybrid-Observer bereits im <head> starten kann.

ESM

import { createConsentManager } from 'tiny-consent';

const consent = createConsentManager({
  version: 1,
  mode: 'hybrid',
  presets: ['youtube', 'googleMaps'],
});

consent.init();

Presets

v0.6 enthält:

presets: [
  'youtube',
  'vimeo',
  'googleMaps',
  'googleFonts',
  'ga4',
]

Presets registrieren Service-Metadaten, Purpose und URL-Matches. Eigene Konfiguration überschreibt Preset-Werte:

createConsentManager({
  version: 1,
  mode: 'hybrid',
  presets: ['youtube'],

  services: {
    youtube: {
      description: 'Unser eigener Beschreibungstext.'
    }
  }
});

Eigene Auto-Regeln

Jeder Service kann eigene Match-Regeln definieren:

services: {
  supportWidget: {
    title: 'Support Widget',
    purpose: 'external',
    match: [
      'widget.example.com/',
      '*.support.example.net'
    ],
    resources: ['script', 'iframe']
  }
}

match verwendet bewusst einfache, transparente Regeln:

  • normaler String → Teilstring-Match gegen die URL
  • *.example.com → Host-Wildcard

Manuelles Markup gewinnt

<script
  type="text/plain"
  data-consent="mySpecialService"
  data-src="https://cdn.example.com/widget.js">
</script>

Auch wenn die URL zu einem Preset passen würde, wird die explizite Service-Zuordnung nicht überschrieben.

Dynamische Ressourcen

Das ist der stärkste Auto-Anwendungsfall:

const iframe = document.createElement('iframe');
iframe.src = 'https://www.youtube-nocookie.com/embed/VIDEO_ID';
document.body.appendChild(iframe);

Im Hybrid-Modus prüft Tiny Consent das Element vor appendChild(). Ohne YouTube-Consent wird src zwischengespeichert, das Element blockiert und später bei Zustimmung aktiviert.

Debug-Modus

debug: true

Beispiele:

[tiny-consent] DETECTED iframe https://www.youtube-nocookie.com/... → youtube
[tiny-consent] BLOCKED iframe https://www.youtube-nocookie.com/... → consent missing for youtube
[tiny-consent] UNKNOWN THIRD PARTY → allowed script https://cdn.example.org/foo.js

Unbekannte Ressourcen werden nur gemeldet und nicht blockiert.

Purposes

Purposes bleiben Komfort-Gruppen; gespeichert wird weiterhin nur Consent pro Service:

purposes: {
  external: {
    title: 'Externe Medien'
  }
},
services: {
  customVideo: {
    title: 'Custom Video',
    purpose: 'external'
  }
}
consent.setPurposeConsent('external', true);
consent.hasPurposeConsent('external');

Dependencies und Hooks

services: {
  maps: {
    title: 'Maps'
  },
  mapExtras: {
    title: 'Maps Extras',
    dependsOn: ['maps'],
    onInit(ctx) {},
    onAccept(ctx) {},
    onRevoke(ctx) {}
  }
}

onAccept läuft nur beim Übergang von inaktiv zu effektiv aktiv. onRevoke entsprechend beim Übergang zurück.

Styling

The built-in defaults intentionally use a light, neutral Tailwind/Feather-inspired look (without Tailwind or any icon dependency). trotz Shadow DOM

Die UI bleibt im Shadow DOM gekapselt, stellt aber bewusst CSS Custom Properties am Host bereit. Damit kann die Website das Erscheinungsbild von außen anpassen:

[data-tiny-consent-ui] {
  --tc-accent: #5b3df5;
  --tc-bg: #ffffff;
  --tc-text: #18181b;
  --tc-muted: #71717a;
  --tc-border: #e4e4e7;
  --tc-primary-text: #ffffff;
  --tc-button-bg: #ffffff;
  --tc-button-text: #18181b;
  --tc-button-border: #d4d4d8;
  --tc-backdrop: rgba(0, 0, 0, .55);
  --tc-radius: 12px;
  --tc-button-radius: 8px;
  --tc-font: inherit;
  --tc-banner-width: 960px;
  --tc-dialog-width: 680px;
  --tc-space: .75rem;
}

Weitere Variablen sind --tc-shadow, --tc-dialog-shadow, --tc-focus, --tc-z, --tc-floating-size, --tc-floating-offset, --tc-floating-bg, --tc-floating-text, --tc-floating-border und --tc-floating-shadow. Da Custom Properties über die Shadow-DOM-Grenze vererbt werden, bleibt die interne CSS-Kapselung erhalten.

Für gezielte Änderungen an internen Selektoren kann optional CSS direkt nach den Standardstyles injiziert werden:

createConsentManager({
  version: 1,
  customCss: `
    .tc-banner {
      border-width: 2px;
    }

    .tc-actions .primary {
      font-weight: 700;
    }
  `
});

theme bleibt als Kurzform für häufige Variablen erhalten. Externe CSS-Variablen eignen sich besonders, wenn das Design zentral über das Stylesheet der Website gesteuert werden soll; customCss ist für tiefere UI-Anpassungen gedacht.

Optionaler Floating-CTA

Zusätzlich zu normalen Links oder Buttons mit data-consent-settings kann ein persistenter runder CTA aktiviert werden. Er öffnet denselben Einstellungsdialog und ist standardmäßig deaktiviert:

floatingButton: true

Oder konfiguriert:

floatingButton: {
  enabled: true,
  position: 'bottom-left',
  label: 'Cookie-Einstellungen'
}

Unterstützte Positionen sind bottom-left und bottom-right. Ohne eigenes label wird der lokalisierte Titel der Einstellungen als aria-label und Tooltip verwendet. Das eingebaute Cookie-SVG kann bei Bedarf mit icon durch eigenes vertrauenswürdiges HTML/SVG ersetzt werden.

Styling von außen:

[data-tiny-consent-ui] {
  --tc-floating-size: 52px;
  --tc-floating-offset: 18px;
  --tc-floating-bg: #171717;
  --tc-floating-text: #fff;
  --tc-floating-border: transparent;
  --tc-floating-shadow: 0 10px 30px rgba(0,0,0,.2);
}

Der CTA ist nur eine zusätzliche Einstiegsmöglichkeit. Ein normaler Link bleibt weiterhin möglich:

<a href="#" data-consent-settings>Cookie-Einstellungen</a>

Storage

Local Storage:

storage: {
  type: 'localStorage',
  key: 'tiny-consent'
}

Cookie:

storage: {
  type: 'cookie',
  key: 'tiny-consent',
  cookieDays: 180,
  sameSite: 'Lax',
  secure: true
}

API

consent.init();
consent.destroy();
consent.hasDecision();
consent.hasConsent('youtube');
consent.hasDirectConsent('youtube');
consent.hasPurposeConsent('external');
consent.setConsent('youtube', true);
consent.setPurposeConsent('external', true);
consent.acceptAll();
consent.rejectAll();
consent.showSettings();
consent.sync();
consent.reset();
consent.getState();

Demo-Dateien

  • index.html Vite/TypeScript-Demo mit Auto + Manual nebeneinander
  • standalone.html klassische Script-Integration, Hybrid-Bootstrap früh im <head>

Datenschutz-Hinweis

Die Library liefert technische Consent- und Blocking-Mechanik. Ob eine konkrete Implementierung DSGVO/ePrivacy-konform ist, hängt unter anderem von den eingesetzten Diensten, Rechtsgrundlagen, Texten, Widerrufsmöglichkeiten und der tatsächlichen Netzwerkaktivität der Website ab.

Motion

Die Default-UI nutzt kurze, subtile Transitionen für Dialog, Backdrop, Banner, Floating-CTA, Buttons, Switches und Auto-Placeholder. Über prefers-reduced-motion: reduce werden diese Animationen automatisch deaktiviert. Die Timing-Variablen --tc-motion-fast, --tc-motion, --tc-ease und --tc-ease-out können am UI-Host überschrieben werden.