Skip to content

Instantly share code, notes, and snippets.

@dragontheory
Created April 25, 2025 13:20
Show Gist options
  • Save dragontheory/fbffe80362197111233610071cf46d2c to your computer and use it in GitHub Desktop.
Save dragontheory/fbffe80362197111233610071cf46d2c to your computer and use it in GitHub Desktop.

💡 What Does "Declarative" Mean?

Date: 2025-04-25

In web development, declarative means expressing desired outcomes using standard browser features—without scripting how to achieve them.

You describe what the browser should do. The browser handles how to do it.

By contrast, imperative code tells the browser step-by-step how to perform a task using JavaScript or external logic.


⚙️ Why It Matters

Declarative features are:

  • 🧬 Native: Part of HTML/CSS specifications
  • 🚀 Performant: Handled directly by the rendering engine
  • Accessible: Align with browser + assistive tech behaviors
  • 🧹 Maintainable: Easier to read, scale, and debug

Declarative doesn’t mean limited—browsers continue to add expressive power (e.g. :has(), container queries, content visibility, native validation).


✍️ Example: Required Field

✅ Declarative

<form>
  <label for="email">Email</label>
  <input id="email" type="email" required>
  <button>Submit</button>
</form>

⚠️ Imperative

<input id="email">
<button onclick="validate()">Submit</button>

<script>
  function validate() {
    const email = document.getElementById('email')
    if (!email.value) {
      alert('Email is required')
    }
  }
</script>

🔁 Example: Toggling Visibility

✅ Declarative

<details>
  <summary>Advanced Settings</summary>
  <fieldset>
    <label><input type="checkbox"> Enable Logs</label>
  </fieldset>
</details>

⚠️ Imperative

<button onclick="toggle()">Advanced Settings</button>
<div id="settings" hidden>
  <label><input type="checkbox"> Enable Logs</label>
</div>

<script>
  function toggle() {
    const el = document.getElementById('settings')
    el.hidden = !el.hidden
  }
</script>

🎨 Declarative in CSS

form:has(input:invalid) button {
  opacity: 0.5;
  pointer-events: none;
}

This CSS-only rule disables the submit button until all inputs are valid—no JS required.


🌍 Real-World Benefits

✅ Benefit 🌟 How It Helps
🔄 Predictability Browsers already know how to render and handle native behavior
♿ Accessibility Works out-of-the-box with AT (e.g. screen readers)
🧹 Maintenance Fewer moving parts, easier audits
🚀 Performance No runtime JS for basic behavior
📱 Interop Compatible across modern devices and input types

🚫 When Declarative Is Not Enough

Imperative logic may still be necessary for:

  • 🗄️ Data layer logic (e.g. CRUD ops, fetch, parse, cache)
  • 🧠 Business rules (e.g. role-based access, pricing conditions)
  • 🌐 External integrations (e.g. analytics, API gateways)
  • 💾 Non-DOM state (e.g. service workers, app-level persistence)

🧠 Note: GUI state is now fully declarative.

Modern CSS handles all visual and interactive UI states natively using:

  • :has()
  • :checked, :valid, :invalid, :empty
  • :target, :focus-within, :not(:empty)
  • Container queries (@container, container-type)
  • Style queries (@container style(...))
  • Logical properties (e.g. block-size, inline-size)

This eliminates the need for JS-based state machines, toggling classes, or imperative DOM manipulation for GUI state.


📚 Recommended Resources

  1. Declarative Programming and the Web – Smashing Magazine
    Explores declarative paradigms in web development, contrasting them with imperative logic.

  2. Declarative Shadow DOM – web.dev
    Details how modern browsers implement declarative shadow DOM for encapsulated UI components.

  3. HTML: A Good Basis for Accessibility – MDN Web Docs
    Emphasizes how semantic HTML contributes to accessibility by design.

  4. Declarative Design – Jeremy Keith
    Advocates for native HTML and CSS as the foundation for resilient, maintainable web interfaces.


🧾 Summary

🔒 Minimizing external dependencies—beyond the native browser—is a strategic choice for long-term stability and maintainability. The browser is our one true dependency. Relying on it directly enables longevity, future-proofing, and avoids entanglements with third-party tooling that may change, deprecate, or fragment over time.

Declarative development isn’t about avoiding code—it’s about writing less of it by leveraging built-in capabilities.

It leads to faster, more stable, and more accessible interfaces, while preserving full control over business logic where needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment