Skip to content

Instantly share code, notes, and snippets.

@dragontheory
Created March 28, 2025 20:07
Show Gist options
  • Save dragontheory/a63f66b3d7f7b79fd1c8d5ca2696641e to your computer and use it in GitHub Desktop.
Save dragontheory/a63f66b3d7f7b79fd1c8d5ca2696641e to your computer and use it in GitHub Desktop.

🧩 UI Is Not UX

Author: D7460N
Context: Architecture principles for framework agnostic, standards-based, role-aware, accessible SPAs


🧠🖼️ UI Is Not UX

UI (User Interface) is what users see and interact with 🖱️. It’s the visible structure: HTML markup, CSS styles, and controls that expose functionality.

UX (User Experience) is how it all works and feels 🎯—spanning perception, trust, utility, and usability across the user’s journey.

Conflating the two often leads to premature styling, incorrect affordances, and inaccessible workflows that fail when CSS breaks or the user’s context changes (e.g. screen readers, keyboard nav, or degraded network conditions). Separating UI from UX is not just good practice—it’s foundational to resilient, adaptive design 🛠️.


✂️ Why They Should Be Separated

  • UI ≠ Presentation Layer Only
    The UI should represent state 🔁, not enforce it. CSS should reflect app state declaratively (e.g. :has([aria-busy="true"])) without hardcoded logic.

  • UX = Behavior + Heuristics
    UX is defined by timing, expectations, and reactions ⏱️🤝. This includes:

    • Loading feedback
    • Navigation clarity
    • Error prevention and recovery
    • Consistency and predictability
    • Accessibility at every step ♿ (per WCAG 2.2 and heuristic evaluation standards)
  • 🧱 UI lives in HTML/CSS. UX spans across structure, behavior, and content.


⚙️ In Practice

  • 🧬 UI Layer = HTML + CSS

    • All structural semantics handled in HTML (<nav>, <section>, <aside>, etc.) 🏗️
    • All behavior signaling handled in CSS using state selectors like :has(), [hidden], and container queries 🎛️
    • UI updates are a consequence of state—not a controller of it 🎯
  • 🧠 UX Layer = Data, Heuristics, and Feedback

    • Data fetched and injected via JavaScript 📨
    • UX patterns (e.g. CRUD actions, filters, sort) designed for discoverability, clarity, and speed 🔍⚡
    • Role-aware flows implemented declaratively: users see only what they can act on 🧑‍💼
    • All feedback (e.g. loading states, errors, empty states) exposed to screen readers and non-visual users 🗣️👂

💡 Example

Bad:

<div class="loading">Loading...</div>
if (loading) document.querySelector(".loading").classList.add("show")

Good (UI separated from UX):

<output aria-busy="true" hidden>Loading data…</output>
:has([aria-busy="true"]) output {
  display: block;
}
output.hidden = false
output.setAttribute("aria-busy", true)

Now:

  • The UI reacts to the state 🔁.
  • The UX (user experience) of “loading” is exposed to all users—visually and via assistive tech 🔊.

🧭 ## Final Principle

UI is how it looks. UX is how it works.
UI changes style. UX changes outcomes.

A screen that "looks right" but can’t be used (or breaks under edge cases) is a UI, but it’s not UX.

Good UX begins where styling ends—with intent, resilience, and inclusiveness built from the architecture up 🏗️🔐.

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