- TypeScript 88.2%
- HTML 9.6%
- JavaScript 2.2%
| src | ||
| .gitignore | ||
| build.mjs | ||
| CHANGELOG.md | ||
| index.html | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| standalone.html | ||
| tsconfig.esm.json | ||
| tsconfig.json | ||
| tsconfig.types.json | ||
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]undimg[src] - Blocking dynamisch eingefügter Ressourcen vor
appendChild/insertBefore/replaceChild MutationObserverfü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 nebeneinanderstandalone.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.