Demfati Widget Documentation v1
Drop-in, zero-dependency JavaScript library that safely embeds Demfati-powered widgets (Voting, Tickets, Forms, etc.) into any website with lazy-loading, caching, and automatic domain verification.
- 🚀 Works with any front-end stack (HTML, React, Vue, WordPress, …)
- ⚡ Lazy-loads widgets only when they enter the viewport
- 🧩 Two lines of code to render a fully-functional ticket shop or voting gallery
- 🔒 Whitelist-based domain security (meta-tag verification)
- 📱 Responsive skeleton screens & dark-mode-ready CSS
- 🌍 Built-in internationalization helpers & currency formatting
Quick Start (60 seconds)
1. Verify your domain
Add this meta tag to the <head> of every page that will host a widget:
<meta name="dmf-domain-verification" content="YOUR_SITE_TOKEN">
2. Load the script once
<script src="https://cdn.demfati.com/widgets/demfati-widget.js" defer></script>
3. Place widget(s) anywhere
<!-- Voting gallery -->
<div class="demfati-widget" data-type="voting" data-request="EVENT_CODE"></div>
<!-- Ticket store -->
<div class="demfati-widget" data-type="tickets" data-request="EVENT_CODE"></div>
<!-- Form plugin -->
<div class="demfati-widget" data-type="forms" data-request="FORM123"></div>
4. Initialize (optional)
<script>
document.addEventListener('DOMContentLoaded', () => {
dmfwl.init({
sort: 'votes', // name | code | votes
search: true // show search bar inside voting widget
});
});
</script>
Tip: You can skip init(/**CONFIGURATION**/) entirely, widgets load with sensible defaults.
Domain Verification
For security, every API response is scoped to whitelisted domains. The loader refuses to render if the meta tag is missing or invalid.
| Attribute | Value |
|---|---|
name | dmf-domain-verification |
content | Site token from Demfati dashboard → Settings → Domains |
The token is tied to your account, not to a single event—reuse it across all pages.
Available Widgets
1. Voting / Contest Gallery
Searchable, sortable grid of contestants with vote counts, progress bars, one-click payment (cards, USSD, Apple Pay, Google Pay, WhatsApp).
<div class="demfati-widget" data-type="voting" data-request="MISS_WORLD_2025"></div>
2. Ticket Store
Complete checkout: ticket selection, attendee forms, order summary, payment (PayStack, Flutterwave, Stripe, WhatsApp), auto-generated QR/Bar-coded tickets.
<div class="demfati-widget" data-type="tickets" data-request="TEDX_UNILAG"></div>
3. Form Attachment
Feedback, survey, payment, auto-confirmation.
<div class="demfati-widget" data-type="forms" data-request="FORM123"></div>
Init Options
All keys are optional.
| Key | Type | Default | Description |
|---|---|---|---|
sort | 'name'|'code'|'votes' | original | Initial contestant order |
search | boolean | true | Show/hide search bar (voting widget) |
customRenderContestant | function | — | Override contestant card HTML |
API Reference
The global dmfwl instance exposes:
dmfwl.init(options?)
dmfwl.init(options?)Bootstraps the loader. Safe to call multiple times.
dmfwl.loadFromCache(key) → any | null
dmfwl.loadFromCache(key) → any | nullLow-level cached API responses (10 min TTL).
dmfwl.saveToCache(key, data)
dmfwl.saveToCache(key, data)Programmatically store JSON (10 min TTL).
Code Examples
React (Next.js)
import { useEffect } from 'react';
export default function Home() {
useEffect(() => {
import('https://cdn.demfati.com/widgets/demfati-widget.js').then(() => dmfwl.init({ sort: 'votes' }));
}, []);
return <div className="demfati-widget" data-type="tickets" data-request="NEXT_CONF_2025"></div>;
}
Vue 3 (Composition API)
<template><div class="demfati-widget" data-type="voting" data-request="HACKATHON_2025"></div></template>
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
const script = document.createElement('script');
script.src = 'https://cdn.demfati.com/widgets/demfati-widget.js';
script.onload = () => dmfwl.init({ search: true });
document.head.appendChild(script);
});
</script>
WordPress (Classic Editor)
<meta name="dmf-domain-verification" content="YOUR_TOKEN">
<script src="https://cdn.demfati.com/widgets/demfati-widget.js" defer></script>
<div class="demfati-widget" data-type="tickets" data-request="WORDCAMP_LAGOS"></div>
Styling & Theming
All widgets ship with neutral, adaptive CSS. Override any rule—every visual token is exposed as a custom property or class.
/* Brand header */
.dmf-ticket-header{background:linear-gradient(135deg,var(--primary),#fff)}
/* Custom button */
.dmf-ticket-form .btn-primary{background:#7c3aed;box-shadow:0 4px 14px rgba(124,58,237,.4)}
/* Skeleton */
.dmf-skel-ticket-card{background:#f1f5f9}
Supply customRenderContestant and skip default CSS entirely for full control.
FAQ / Troubleshooting
Widget never appears?
- DevTools → Console: add the meta tag if you see “Domain verification meta tag missing”.
- Ensure
data-requestis a valid event code. - Check CSP isn’t blocking the script.
Can I lazy-load the script itself?
Yes – < 6 kB gzipped, safe with async/defer or dynamic import.
Does it work offline?
Cached responses served from localStorage while online; true offline (SW) on roadmap.
React/Vue wrapper?
Official wrappers coming soon – use vanilla snippet inside useEffect/onMounted for now.
