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:

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

LineWhat 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:

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.