Back to all docs

iMessage-like Chat UI: Vanilla HTML/CSS/JS Design Decision

Date: November 2025 Project: Chat App PWA Decision: Use vanilla HTML/CSS/JS instead of frameworks (React, Vue, Next.js, etc.)


Context

Building a modern, native-feeling chat interface for iOS that works as a Progressive Web App. Goal is to achieve iMessage-like smoothness and polish while maintaining simplicity and performance.


Decision: Vanilla HTML/CSS/JS

We chose to build with no frameworks - pure web standards only.

Technology Stack

Total bundle size: ~20KB (HTML + CSS + JS combined)


Why Vanilla Won

1. Performance

Our metrics:

Framework comparison:

For a single-page chat interface, this overhead buys us nothing.

2. Simplicity & Control

What we have:

Framework complexity we avoided:

3. Longevity & Maintenance

Vanilla advantages:

Framework maintenance burden:

4. PWA & iOS Optimization

Our setup:

Framework PWA challenges:

5. Development Speed (For This Project)

Our approach:

Framework approach would require:

For a single-page chat UI, vanilla was faster to build and iterate.


Where Frameworks Would Win

We're honest about the trade-offs. Frameworks would be better if we had:

1. Complex State Management

Would benefit from React/Vue if:

Current reality:

2. Many Reusable Components

Would benefit from components if:

Current reality:

3. Routing & Multiple Views

Would benefit from framework routing if:

Current reality:

4. Type Safety at Scale

Would benefit from TypeScript + React if:

Current reality:

5. Server-Side Rendering

Would benefit from Next.js if:

Current reality:


When To Reconsider

Red Flags That Framework Might Be Worth It

State complexity:

Scale:

Backend integration:

Team:

Green Lights To Stay Vanilla

Simple additions:

As long as:


Current Metrics (Baseline for Future Comparison)

Performance

Code Metrics

Test Coverage

Development Velocity


Lessons Learned

What Worked Well

  1. Direct DOM manipulation is fine - No virtual DOM needed for this
  2. CSS is powerful - Modern CSS handles 90% of what frameworks do
  3. Native events are sufficient - No need for synthetic events
  4. Service workers are straightforward - Framework abstraction adds little value
  5. Testing is easier - No mocking framework internals

What Was Harder Than Framework

  1. No component reuse patterns - Had to write custom patterns for message bubbles
  2. Manual DOM updates - Had to track what needs updating ourselves
  3. No developer tooling - No React DevTools, Vue DevTools equivalents

What We'd Do Different

  1. Consider TypeScript - Type safety without framework overhead
  2. Maybe use a micro-library - Something like Preact (3KB) if we add complexity
  3. Better state patterns - Could use observer pattern or custom state manager

Recommendation for Future

Continue with Vanilla If:

Switch to Framework If:

Hybrid Approach (Consider Later):


Alternatives Considered

1. React

Pros: Huge ecosystem, familiar to many devs, great tooling Cons: 130KB+ overhead, build complexity, overkill for single view Verdict: Not worth it for current scope

2. Vue

Pros: Smaller than React, simpler learning curve, good reactivity Cons: Still 80KB+, build step required, unnecessary for our needs Verdict: Better than React but still overkill

3. Svelte

Pros: Compiles away (small bundle), great DX, reactive by default Cons: Build step required, less mature ecosystem, still learning curve Verdict: Most compelling framework option, but vanilla is still simpler

4. Next.js

Pros: Full-stack, great DX, SSR/SSG capabilities Cons: 200KB+, massive overkill, server complexity we don't need Verdict: Wrong tool for this job

5. Preact

Pros: Only 3KB, React-compatible API, fast Cons: Still need JSX build step, adds complexity we don't need yet Verdict: Good middle ground if vanilla becomes too complex

6. Alpine.js / htmx

Pros: Minimal, progressive enhancement, no build Cons: Still external dependencies, limited for complex UIs Verdict: Interesting but vanilla gives us more control


Technical Deep Dive: Why Performance Matters

Mobile Performance Reality

Our Performance Wins

  1. Zero framework parsing - Browser runs our code directly
  2. Minimal cache footprint - More room for message cache
  3. No virtual DOM diffing - Direct DOM updates are faster for our use case
  4. CSS animations - GPU accelerated, no JS overhead
  5. Lazy loading - Only load what we need, when we need it

Real-World Impact


Conclusion

For this chat app, vanilla HTML/CSS/JS is objectively the right choice.

We get:

We sacrifice:

Re-evaluate when:

Until then: Keep it vanilla. Keep it simple. Keep it fast.


Last updated: November 2025 Next review: When adding backend integration or when team/scope changes significantly