Forms & Events

Two-way data binding, form handling, and event management

Form attributes enable interactive forms with two-way data binding, event handling, and error display. These transform static forms into dynamic, data-driven interfaces.

dbind_model

Purpose: Create two-way data binding between form inputs and data. Changes to the input update the data, and changes to the data update the input.

Syntax:

<input dbind_model="fieldName">
<textarea dbind_model="fieldName"></textarea>
<select dbind_model="fieldName"></select>

How Two-Way Binding Works

┌─────────────┐     ┌─────────────┐
│  User Input │ ──► │    Data     │
│   (typing)  │     │   (state)   │
└─────────────┘     └──────┬──────┘
       ▲                   │
       │                   │
       └───────────────────┘
         Data updates input
  1. User types in the input
  2. Data is automatically updated
  3. Any elements bound to the same data are updated
  4. If data changes programmatically, the input updates

Supported Input Types

Input TypeExample
text<input type="text" dbind_model="name">
email<input type="email" dbind_model="email">
password<input type="password" dbind_model="password">
number<input type="number" dbind_model="quantity">
tel<input type="tel" dbind_model="phone">
url<input type="url" dbind_model="website">
search<input type="search" dbind_model="query">
textarea<textarea dbind_model="message"></textarea>
select<select dbind_model="country">...</select>
checkbox<input type="checkbox" dbind_model="agree">
radio<input type="radio" dbind_model="choice">

Basic Usage

<!-- Text input -->
<input type="text" dbind_model="username" placeholder="Username">
 
<!-- Display the bound value -->
<p>Hello, <span dbind_data="username"></span>!</p>

As the user types in the input, the greeting updates in real-time.

Text Inputs

<form class="contact-form">
  <div class="form-group">
    <label for="name">Name</label>
    <input type="text" id="name" dbind_model="form.name" required>
  </div>
 
  <div class="form-group">
    <label for="email">Email</label>
    <input type="email" id="email" dbind_model="form.email" required>
  </div>
 
  <div class="form-group">
    <label for="message">Message</label>
    <textarea id="message" dbind_model="form.message" rows="5"></textarea>
  </div>
</form>

Data:

{
  "form": {
    "name": "",
    "email": "",
    "message": ""
  }
}

Checkbox Binding

For checkboxes, dbind_model binds to a boolean value:

<!-- Single checkbox (boolean) -->
<label>
  <input type="checkbox" dbind_model="newsletter">
  Subscribe to newsletter
</label>
 
<!-- The value -->
<span dbind_data="newsletter"></span> <!-- outputs: true or false -->

Radio Button Binding

Radio buttons bind to the selected value:

<fieldset>
  <legend>Select your plan:</legend>
 
  <label>
    <input type="radio" name="plan" value="free" dbind_model="selectedPlan">
    Free
  </label>
 
  <label>
    <input type="radio" name="plan" value="pro" dbind_model="selectedPlan">
    Pro ($9/month)
  </label>
 
  <label>
    <input type="radio" name="plan" value="enterprise" dbind_model="selectedPlan">
    Enterprise ($49/month)
  </label>
</fieldset>
 
<p>Selected plan: <span dbind_data="selectedPlan"></span></p>

Select Dropdowns

<div class="form-group">
  <label for="country">Country</label>
  <select id="country" dbind_model="selectedCountry">
    <option value="">Select a country</option>
    <option value="us">United States</option>
    <option value="uk">United Kingdom</option>
    <option value="ca">Canada</option>
    <option value="au">Australia</option>
  </select>
</div>
 
<p>You selected: <span dbind_data="selectedCountry"></span></p>

Dynamic Select Options

Populate select options from data:

<select dbind_model="selectedCategory">
  <option value="">Choose a category</option>
  <option dbind_repeat="categories" dbind_data="name" value="{{id}}"></option>
</select>

Data:

{
  "categories": [
    { "id": "tech", "name": "Technology" },
    { "id": "fashion", "name": "Fashion" },
    { "id": "home", "name": "Home & Garden" }
  ],
  "selectedCategory": ""
}

Use Cases

1. Live Search Preview

<div class="search-container">
  <input type="search" dbind_model="searchQuery" placeholder="Search...">
 
  <div class="search-preview" dbind_show="searchQuery">
    Searching for: "<span dbind_data="searchQuery"></span>"
  </div>
</div>

2. Character Counter

<div class="textarea-container">
  <textarea
    dbind_model="bio"
    maxlength="280"
    placeholder="Tell us about yourself..."
  ></textarea>
  <div class="character-count">
    <span dbind_data="bio.length">0</span>/280 characters
  </div>
</div>

3. Live Form Preview

<div class="profile-editor">
  <!-- Form -->
  <form class="edit-form">
    <input type="text" dbind_model="profile.name" placeholder="Name">
    <input type="text" dbind_model="profile.title" placeholder="Job Title">
    <textarea dbind_model="profile.bio" placeholder="Bio"></textarea>
    <input type="url" dbind_model="profile.website" placeholder="Website">
  </form>
 
  <!-- Live Preview -->
  <div class="preview-card">
    <h3 dbind_data="profile.name" dbind_default="Your Name"></h3>
    <span class="title" dbind_data="profile.title" dbind_default="Job Title"></span>
    <p dbind_data="profile.bio" dbind_default="Your bio goes here..."></p>
    <a dbind_href="profile.website" dbind_show="profile.website">Website</a>
  </div>
</div>

4. Settings Toggle

<div class="settings">
  <h2>Notification Settings</h2>
 
  <label class="setting-row">
    <input type="checkbox" dbind_model="settings.emailNotifications">
    <span>Email notifications</span>
  </label>
 
  <label class="setting-row">
    <input type="checkbox" dbind_model="settings.pushNotifications">
    <span>Push notifications</span>
  </label>
 
  <label class="setting-row">
    <input type="checkbox" dbind_model="settings.weeklyDigest">
    <span>Weekly digest</span>
  </label>
 
  <!-- Show summary -->
  <div class="settings-summary">
    <p dbind_show="settings.emailNotifications">✓ Email notifications enabled</p>
    <p dbind_show="settings.pushNotifications">✓ Push notifications enabled</p>
    <p dbind_show="settings.weeklyDigest">✓ Weekly digest enabled</p>
  </div>
</div>

5. Conditional Form Fields

<form class="registration-form">
  <select dbind_model="accountType">
    <option value="personal">Personal</option>
    <option value="business">Business</option>
  </select>
 
  <!-- Show only for business accounts -->
  <div class="business-fields" dbind_if="accountType==business">
    <input type="text" dbind_model="companyName" placeholder="Company Name">
    <input type="text" dbind_model="taxId" placeholder="Tax ID">
    <input type="text" dbind_model="industry" placeholder="Industry">
  </div>
 
  <!-- Show only for personal accounts -->
  <div class="personal-fields" dbind_if="accountType==personal">
    <input type="date" dbind_model="birthday" placeholder="Birthday">
  </div>
</form>

dbind_submit

Purpose: Handle form submission and send data to a specified endpoint.

Syntax:

<form dbind_submit="endpoint">
  <!-- form fields -->
</form>

How It Works

  1. User submits the form
  2. DBindly prevents default submission
  3. Collects all dbind_model values
  4. Sends data to the specified endpoint
  5. Handles response (success/error)

Basic Usage

<form dbind_submit="/api/contact">
  <input type="text" dbind_model="name" placeholder="Name" required>
  <input type="email" dbind_model="email" placeholder="Email" required>
  <textarea dbind_model="message" placeholder="Message" required></textarea>
 
  <button type="submit">Send Message</button>
</form>

Handling Submission States

<form dbind_submit="/api/newsletter">
  <input type="email" dbind_model="email" placeholder="Enter your email" required>
  <button type="submit" dbind_hide="isSubmitting">Subscribe</button>
  <button type="button" disabled dbind_show="isSubmitting">Sending...</button>
</form>
 
<!-- Success message -->
<div class="success-message" dbind_show="submitSuccess">
  Thank you for subscribing!
</div>
 
<!-- Error message -->
<div class="error-message" dbind_show="submitError">
  Something went wrong. Please try again.
</div>

Use Cases

1. Contact Form

<form dbind_submit="/api/contact" class="contact-form">
  <div class="form-group">
    <label for="contact-name">Name *</label>
    <input
      type="text"
      id="contact-name"
      dbind_model="contact.name"
      required
    >
    <span class="error" dbind_error-field="name"></span>
  </div>
 
  <div class="form-group">
    <label for="contact-email">Email *</label>
    <input
      type="email"
      id="contact-email"
      dbind_model="contact.email"
      required
    >
    <span class="error" dbind_error-field="email"></span>
  </div>
 
  <div class="form-group">
    <label for="contact-subject">Subject</label>
    <select id="contact-subject" dbind_model="contact.subject">
      <option value="general">General Inquiry</option>
      <option value="support">Support</option>
      <option value="sales">Sales</option>
    </select>
  </div>
 
  <div class="form-group">
    <label for="contact-message">Message *</label>
    <textarea
      id="contact-message"
      dbind_model="contact.message"
      rows="5"
      required
    ></textarea>
    <span class="error" dbind_error-field="message"></span>
  </div>
 
  <button type="submit" dbind_hide="isSubmitting">
    Send Message
  </button>
  <button type="button" disabled dbind_show="isSubmitting">
    Sending...
  </button>
</form>
 
<div class="form-success" dbind_show="submitSuccess">
  <h3>Message Sent!</h3>
  <p>We'll get back to you within 24 hours.</p>
</div>

2. Newsletter Signup

<form dbind_submit="/api/newsletter" class="newsletter-form">
  <div class="input-group">
    <input
      type="email"
      dbind_model="newsletter.email"
      placeholder="Enter your email"
      required
    >
    <button type="submit" dbind_hide="isSubmitting">Subscribe</button>
  </div>
 
  <label class="consent">
    <input type="checkbox" dbind_model="newsletter.consent" required>
    I agree to receive marketing emails
  </label>
 
  <div class="form-messages">
    <p class="success" dbind_show="submitSuccess">
      Thanks for subscribing! Check your inbox to confirm.
    </p>
    <p class="error" dbind_error></p>
  </div>
</form>

3. Feedback Form

<form dbind_submit="/api/feedback" class="feedback-form">
  <h3>How was your experience?</h3>
 
  <div class="rating-group" role="radiogroup">
    <label>
      <input type="radio" name="rating" value="5" dbind_model="feedback.rating">
      <span>5 - Excellent</span>
    </label>
    <label>
      <input type="radio" name="rating" value="4" dbind_model="feedback.rating">
      <span>4 - Good</span>
    </label>
    <label>
      <input type="radio" name="rating" value="3" dbind_model="feedback.rating">
      <span>3 - Average</span>
    </label>
    <label>
      <input type="radio" name="rating" value="2" dbind_model="feedback.rating">
      <span>2 - Poor</span>
    </label>
    <label>
      <input type="radio" name="rating" value="1" dbind_model="feedback.rating">
      <span>1 - Terrible</span>
    </label>
  </div>
 
  <div class="form-group">
    <label>Any additional comments?</label>
    <textarea dbind_model="feedback.comments" rows="3"></textarea>
  </div>
 
  <button type="submit">Submit Feedback</button>
</form>

dbind_click

Purpose: Handle click events on any element and trigger an action.

Syntax:

<element dbind_click="actionName"></element>
<element dbind_click="actionName:param"></element>

Basic Usage

<!-- Simple click action -->
<button dbind_click="increment">+1</button>
<button dbind_click="decrement">-1</button>
<span dbind_data="count">0</span>

Click with Parameters

<!-- Pass parameters to the action -->
<button dbind_click="addToCart:{{productId}}">Add to Cart</button>
<button dbind_click="setQuantity:5">Set to 5</button>

Use Cases

1. Counter

<div class="counter">
  <button dbind_click="decrement" class="btn-minus"></button>
  <span dbind_data="count">0</span>
  <button dbind_click="increment" class="btn-plus">+</button>
</div>

2. Toggle Visibility

<button dbind_click="toggleDetails">
  <span dbind_hide="showDetails">Show Details</span>
  <span dbind_show="showDetails">Hide Details</span>
</button>
 
<div class="details" dbind_show="showDetails">
  <p>Here are the details...</p>
</div>

3. Tab Navigation

<div class="tabs">
  <button dbind_click="setTab:overview" dbind_class="activeTabClass">Overview</button>
  <button dbind_click="setTab:features" dbind_class="activeTabClass">Features</button>
  <button dbind_click="setTab:specs" dbind_class="activeTabClass">Specs</button>
</div>
 
<div class="tab-content">
  <div dbind_if="activeTab==overview">
    <h3>Overview</h3>
    <p>Product overview content...</p>
  </div>
  <div dbind_if="activeTab==features">
    <h3>Features</h3>
    <ul>
      <li>Feature 1</li>
      <li>Feature 2</li>
    </ul>
  </div>
  <div dbind_if="activeTab==specs">
    <h3>Specifications</h3>
    <table>...</table>
  </div>
</div>

4. Quick Actions

<div class="product-card">
  <h3 dbind_data="name"></h3>
  <div class="quick-actions">
    <button dbind_click="addToCart:{{id}}" title="Add to Cart">🛒</button>
    <button dbind_click="addToWishlist:{{id}}" title="Add to Wishlist">❤️</button>
    <button dbind_click="quickView:{{id}}" title="Quick View">👁️</button>
  </div>
</div>

5. Quantity Selector

<div class="quantity-selector">
  <button dbind_click="decreaseQuantity" dbind_unless="quantity<=1"></button>
  <input type="number" dbind_model="quantity" min="1" max="99">
  <button dbind_click="increaseQuantity" dbind_unless="quantity>=99">+</button>
</div>

dbind_error

Purpose: Display general error messages from form submissions or API calls.

Syntax:

<element dbind_error></element>
<element dbind_error="customErrorField"></element>

Basic Usage

<form dbind_submit="/api/login">
  <input type="email" dbind_model="email" placeholder="Email">
  <input type="password" dbind_model="password" placeholder="Password">
  <button type="submit">Login</button>
 
  <!-- General error message -->
  <div class="error-message" dbind_error>
    <!-- Error text appears here -->
  </div>
</form>

Styling Error Messages

<form dbind_submit="/api/register">
  <!-- Form fields -->
 
  <div class="error-container" dbind_show="hasError">
    <span class="error-icon">⚠️</span>
    <p class="error-text" dbind_error></p>
    <button class="dismiss" dbind_click="clearError">×</button>
  </div>
</form>

CSS:

.error-container {
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  padding: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  color: #dc2626;
}

dbind_error-field

Purpose: Display field-specific validation error messages.

Syntax:

<element dbind_error-field="fieldName"></element>

Basic Usage

<form dbind_submit="/api/register">
  <div class="form-group">
    <label for="username">Username</label>
    <input type="text" id="username" dbind_model="username" required>
    <span class="field-error" dbind_error-field="username"></span>
  </div>
 
  <div class="form-group">
    <label for="email">Email</label>
    <input type="email" id="email" dbind_model="email" required>
    <span class="field-error" dbind_error-field="email"></span>
  </div>
 
  <div class="form-group">
    <label for="password">Password</label>
    <input type="password" id="password" dbind_model="password" required>
    <span class="field-error" dbind_error-field="password"></span>
  </div>
 
  <button type="submit">Register</button>
</form>

Complete Form with Validation

<form dbind_submit="/api/register" class="registration-form">
  <!-- Username -->
  <div class="form-group">
    <label for="reg-username">Username *</label>
    <input
      type="text"
      id="reg-username"
      dbind_model="registration.username"
      minlength="3"
      maxlength="20"
      required
    >
    <small class="helper-text">3-20 characters, letters and numbers only</small>
    <span class="field-error" dbind_error-field="username"></span>
  </div>
 
  <!-- Email -->
  <div class="form-group">
    <label for="reg-email">Email Address *</label>
    <input
      type="email"
      id="reg-email"
      dbind_model="registration.email"
      required
    >
    <span class="field-error" dbind_error-field="email"></span>
  </div>
 
  <!-- Password -->
  <div class="form-group">
    <label for="reg-password">Password *</label>
    <input
      type="password"
      id="reg-password"
      dbind_model="registration.password"
      minlength="8"
      required
    >
    <small class="helper-text">At least 8 characters</small>
    <span class="field-error" dbind_error-field="password"></span>
  </div>
 
  <!-- Confirm Password -->
  <div class="form-group">
    <label for="reg-confirm">Confirm Password *</label>
    <input
      type="password"
      id="reg-confirm"
      dbind_model="registration.confirmPassword"
      required
    >
    <span class="field-error" dbind_error-field="confirmPassword"></span>
  </div>
 
  <!-- Terms -->
  <div class="form-group checkbox-group">
    <label>
      <input type="checkbox" dbind_model="registration.agreeTerms" required>
      I agree to the <a href="/terms">Terms of Service</a>
    </label>
    <span class="field-error" dbind_error-field="agreeTerms"></span>
  </div>
 
  <!-- General error -->
  <div class="form-error" dbind_error></div>
 
  <!-- Submit -->
  <button type="submit" dbind_hide="isSubmitting">Create Account</button>
  <button type="button" disabled dbind_show="isSubmitting">Creating...</button>
</form>
 
<!-- Success message -->
<div class="success-panel" dbind_show="submitSuccess">
  <h2>Account Created!</h2>
  <p>Please check your email to verify your account.</p>
</div>

Server Error Response Format:

{
  "error": "Validation failed",
  "fields": {
    "username": "Username is already taken",
    "email": "Please enter a valid email address",
    "password": "Password must contain at least one number"
  }
}

Complete Example: Multi-Step Form

<div class="multi-step-form">
  <!-- Progress indicator -->
  <div class="progress-steps">
    <div class="step" dbind_class="step1Class">
      <span class="step-number">1</span>
      <span class="step-label">Account</span>
    </div>
    <div class="step" dbind_class="step2Class">
      <span class="step-number">2</span>
      <span class="step-label">Profile</span>
    </div>
    <div class="step" dbind_class="step3Class">
      <span class="step-number">3</span>
      <span class="step-label">Preferences</span>
    </div>
  </div>
 
  <!-- Step 1: Account Details -->
  <form class="step-content" dbind_if="currentStep==1">
    <h2>Account Details</h2>
 
    <div class="form-group">
      <label>Email</label>
      <input type="email" dbind_model="form.email" required>
      <span class="error" dbind_error-field="email"></span>
    </div>
 
    <div class="form-group">
      <label>Password</label>
      <input type="password" dbind_model="form.password" required>
      <span class="error" dbind_error-field="password"></span>
    </div>
 
    <div class="form-actions">
      <button type="button" dbind_click="nextStep">Continue</button>
    </div>
  </form>
 
  <!-- Step 2: Profile Info -->
  <form class="step-content" dbind_if="currentStep==2">
    <h2>Profile Information</h2>
 
    <div class="form-row">
      <div class="form-group">
        <label>First Name</label>
        <input type="text" dbind_model="form.firstName" required>
      </div>
      <div class="form-group">
        <label>Last Name</label>
        <input type="text" dbind_model="form.lastName" required>
      </div>
    </div>
 
    <div class="form-group">
      <label>Bio</label>
      <textarea dbind_model="form.bio" rows="3"></textarea>
    </div>
 
    <div class="form-group">
      <label>Location</label>
      <select dbind_model="form.country">
        <option value="">Select country</option>
        <option value="us">United States</option>
        <option value="uk">United Kingdom</option>
        <option value="ca">Canada</option>
      </select>
    </div>
 
    <div class="form-actions">
      <button type="button" dbind_click="prevStep">Back</button>
      <button type="button" dbind_click="nextStep">Continue</button>
    </div>
  </form>
 
  <!-- Step 3: Preferences -->
  <form class="step-content" dbind_if="currentStep==3" dbind_submit="/api/register">
    <h2>Preferences</h2>
 
    <div class="form-group">
      <label>How did you hear about us?</label>
      <select dbind_model="form.referralSource">
        <option value="">Select one</option>
        <option value="google">Google Search</option>
        <option value="friend">Friend/Colleague</option>
        <option value="social">Social Media</option>
        <option value="other">Other</option>
      </select>
    </div>
 
    <div class="form-group checkbox-group">
      <label>
        <input type="checkbox" dbind_model="form.newsletter">
        Subscribe to our newsletter
      </label>
    </div>
 
    <div class="form-group checkbox-group">
      <label>
        <input type="checkbox" dbind_model="form.terms" required>
        I agree to the Terms of Service
      </label>
      <span class="error" dbind_error-field="terms"></span>
    </div>
 
    <div class="form-error" dbind_error></div>
 
    <div class="form-actions">
      <button type="button" dbind_click="prevStep">Back</button>
      <button type="submit" dbind_hide="isSubmitting">Create Account</button>
      <button type="button" disabled dbind_show="isSubmitting">Creating...</button>
    </div>
  </form>
 
  <!-- Success State -->
  <div class="success-state" dbind_show="submitSuccess">
    <div class="success-icon"></div>
    <h2>Welcome aboard!</h2>
    <p>Your account has been created successfully.</p>
    <a href="/dashboard" class="btn-primary">Go to Dashboard</a>
  </div>
</div>

CSS (excerpt):

.multi-step-form {
  max-width: 500px;
  margin: 0 auto;
}
 
.progress-steps {
  display: flex;
  justify-content: space-between;
  margin-bottom: 2rem;
}
 
.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0.5;
}
 
.step.active {
  opacity: 1;
}
 
.step.completed {
  opacity: 1;
  color: #22c55e;
}
 
.step-number {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}
 
.step.active .step-number {
  background: #3b82f6;
  color: white;
}
 
.step.completed .step-number {
  background: #22c55e;
  color: white;
}
 
.form-actions {
  display: flex;
  gap: 1rem;
  justify-content: flex-end;
  margin-top: 2rem;
}

Best Practices

1. Always Provide Feedback

<!-- Good: Show loading and success states -->
<form dbind_submit="/api/save">
  <button dbind_hide="isSubmitting">Save</button>
  <button disabled dbind_show="isSubmitting">Saving...</button>
  <span dbind_show="submitSuccess">✓ Saved!</span>
</form>

2. Use Field-Level Errors

<!-- Good: Error next to the field -->
<div class="form-group">
  <input type="email" dbind_model="email">
  <span class="error" dbind_error-field="email"></span>
</div>

3. Disable Submit While Processing

<button type="submit" dbind_hide="isSubmitting">Submit</button>
<button type="button" disabled dbind_show="isSubmitting">
  <span class="spinner"></span> Processing...
</button>

4. Clear Errors on Input

<input
  type="email"
  dbind_model="email"
  onfocus="clearFieldError('email')"
>

Next Steps