Take it further
Site JS — what a team dev can do
Everything available to a developer on your Bynli-hosted team site — Bootstrap, Font Awesome, twenty-five fonts, modals, toasts, confirms, forms, and the public API — wired together in one real page.
Prereq: set up config.json
first so Bootstrap, icons, and a font are loaded site-wide. The
example below assumes you have
ui in your
ui.load array.
What's on the page
A community-center landing page with a hero, an events grid, a newsletter signup, and a donate flow that uses every part of the kit:
data-bynli-uiauto-loads Bootstrap + Font Awesome + the Bynli fonts- Bootstrap navbar + responsive grid
- Instrument Serif headlines, Inter body
- A Bynli form, Bootstrap-styled, embedded inline
- A donate button that opens a custom modal
- A "remove from mailing list" link with a branded confirm dialog
- Toasts on every success
The full page
Save this as index.html in your site. The
config.json at the root is doing the Bootstrap/fonts loading;
nothing else needed.
<!DOCTYPE html>
<html lang="en" data-bynli-ui="ui,font:inter">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ team.name }} — Community Hub</title>
<style>
body { font-family: "Inter", system-ui, sans-serif; }
h1, h2, .display-1, .display-4 { font-family: "Instrument Serif", Georgia, serif; font-weight: 400; }
.hero { background: #0e0c0a; color: #f5ede0; padding: 6rem 0; }
.hero h1 { font-size: clamp(2.5rem, 6vw, 5rem); line-height: 1.05; }
</style>
</head>
<body>
<!-- ── Bootstrap navbar ─────────────────────────────────── -->
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom">
<div class="container">
<a class="navbar-brand fw-semibold" href="/">{{ team.name }}</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="nav">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link" href="#events">Events</a></li>
<li class="nav-item"><a class="nav-link" href="#newsletter">Newsletter</a></li>
<li class="nav-item">
<button id="donateBtn" class="btn btn-primary ms-2">
<i class="fa-solid fa-heart me-1"></i> Donate
</button>
</li>
</ul>
</div>
</div>
</nav>
<!-- ── Hero ─────────────────────────────────────────────── -->
<section class="hero text-center">
<div class="container">
<h1>Welcome to {{ team.name }}</h1>
<p class="lead opacity-75 col-md-7 mx-auto">{{ team.description }}</p>
<a href="#newsletter" class="btn btn-light btn-lg mt-3">
<i class="fa-solid fa-envelope me-2"></i> Join our newsletter
</a>
</div>
</section>
<!-- ── Events grid (Bootstrap cards) ────────────────────── -->
<section id="events" class="container py-5">
<h2 class="mb-4">Upcoming events</h2>
<div class="row g-4">
<div class="col-md-4">
<div class="card h-100 shadow-sm">
<div class="card-body">
<i class="fa-solid fa-calendar-day fs-3 text-primary mb-2"></i>
<h5 class="card-title">Spring Cleanup</h5>
<p class="card-text text-muted">Saturday, 9am — bring gloves.</p>
<a href="#" class="btn btn-outline-primary btn-sm">RSVP</a>
</div>
</div>
</div>
<!-- repeat ... -->
</div>
</section>
<!-- ── Newsletter form (Bynli form, Bootstrap-styled) ───── -->
<section id="newsletter" class="bg-body-tertiary py-5">
<div class="container col-md-6">
<h2 class="mb-3">Stay in the loop</h2>
<p class="text-muted">One email a week, max. Unsubscribe any time.</p>
<div data-bynli="form"
data-form-id="frm_xxxxxxxxxxxx"
data-form-style="default"
data-form-success="You're on the list — talk soon."
data-form-success-mode="toast"></div>
</div>
</section>
<!-- ── Footer with unsubscribe link ─────────────────────── -->
<footer class="container py-4 text-muted small text-center">
Already on our list?
<a href="#" id="unsubLink">Remove me from the mailing list</a>
</footer>
<script>
// Donate button → custom modal built on the fly
document.getElementById('donateBtn').addEventListener('click', function () {
Bynli.use('modal', 'toast').then(function () {
var m = Bynli.Modal.create({
title: 'Support our work',
body:
'<p class="text-muted">Every dollar funds programming for the kids in our community.</p>' +
'<div class="d-grid gap-2">' +
'<button class="btn btn-primary" data-amt="10"><i class="fa-solid fa-heart me-2"></i>$10</button>' +
'<button class="btn btn-primary" data-amt="50"><i class="fa-solid fa-heart me-2"></i>$50</button>' +
'<button class="btn btn-primary" data-amt="100"><i class="fa-solid fa-heart me-2"></i>$100</button>' +
'</div>',
size: 'sm'
});
m.el.querySelectorAll('[data-amt]').forEach(function (b) {
b.addEventListener('click', function () {
m.close();
Bynli.Toast.success('Thanks! Opening secure checkout for $' + b.dataset.amt + '…');
// Redirect to your real donation endpoint:
// window.location.href = '/donate?amt=' + b.dataset.amt;
});
});
m.open();
});
});
// Unsubscribe link → branded confirm + toast
document.getElementById('unsubLink').addEventListener('click', function (e) {
e.preventDefault();
Bynli.use('confirm', 'toast').then(function () {
Bynli.Confirm.ask(
"We'll remove your email from every future send. You can re-join any time.",
{ title: 'Unsubscribe?', confirmLabel: 'Yes, unsubscribe', danger: true }
).then(function () {
// Hit your unsubscribe endpoint here.
Bynli.Toast.success("You're off the list. Sorry to see you go.");
}).catch(function () { /* cancelled */ });
});
});
// Form success → toast (already requested via data-form-success-mode)
document.addEventListener('bynli:form:submit:success', function (e) {
console.log('Newsletter signup:', e.detail);
});
</script>
</body>
</html>
What's doing what
| Line | What it does |
|---|---|
data-bynli-ui="ui,font:inter" |
runtime.js sees this on <html> and loads Bootstrap + Font Awesome + DM Sans + Instrument Serif + Inter — no <script> or <link> tags needed. |
{{ team.name }} |
Bynli Blocks server-side variable. Renders before the page leaves the server — see Bynli Blocks. |
data-bynli="form" data-form-style="default" |
Fetches the form schema by ID, renders inputs with Bootstrap classes (form-control, btn btn-primary), and POSTs to the public submit endpoint when sent. |
data-form-success-mode="toast" |
On success, show a Bynli toast instead of swapping the form for a success card. |
Bynli.use('modal', 'toast') |
Lazy-loads the two modules just before they're needed. If they're already loaded (because data-bynli="form" already pulled in the toast module), this is a no-op. |
Bynli.Modal.create({...}) |
Builds a branded modal entirely from JS. Returns { el, open, close } so you can wire events to the inner DOM. |
Bynli.Confirm.ask(msg, opts) |
Branded confirm dialog. Resolves on confirm, rejects on cancel. Use danger: true for destructive actions. |
document.addEventListener('bynli:form:submit:success', ...) |
Every form embed dispatches this custom event after a successful submit. e.detail carries the response body — useful for analytics or downstream logic. |
What you don't have to write
The runtime takes care of, automatically:
- Loading
bynli.jsonly when the page actually uses a kit attribute or asset - Page-view ping to your dashboard analytics
- Suspension / maintenance overlay if your site is in either state
- "Powered by Bynli" badge (unless your
config.jsonturns it off and you have the entitlement)
Tip: Open the Network tab on your live site after a
fresh reload. You should see
runtime.js, then a single
config.json fetch, then on-demand requests for each
builder module and asset as the page references them. Nothing more.