Skip to content

Instantly share code, notes, and snippets.

@ests
Created August 19, 2025 09:12
Show Gist options
  • Save ests/a6a72bca1c6095e5dc025d81fbc55884 to your computer and use it in GitHub Desktop.
Save ests/a6a72bca1c6095e5dc025d81fbc55884 to your computer and use it in GitHub Desktop.

Based on the documentation I've reviewed, I can provide you with a comprehensive answer about Stimulus.js and its suitability for working with JSON vs HTML partials in Rails applications.

Stimulus.js Philosophy: HTML-First Approach

Stimulus.js is designed around the "HTML-first" philosophy, which aligns perfectly with the traditional Rails way. Here's what this means for your JSON vs HTML partials question:

HTML Partials (The Rails Way) - Recommended

Stimulus.js works exceptionally well with HTML partials and server-rendered content:

// Content loader controller - fetches HTML fragments
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { url: String }

  connect() {
    this.load()
  }

  load() {
    fetch(this.urlValue)
      .then(response => response.text())  // Note: .text(), not .json()
      .then(html => this.element.innerHTML = html)
  }
}
<div data-controller="content-loader"
     data-content-loader-url-value="/messages.html"></div>

Benefits of this approach:

  • Server-side rendering: Your Rails views handle the HTML generation
  • Progressive enhancement: Works without JavaScript
  • Simpler state management: State lives in the HTML, not JavaScript objects
  • Better SEO: Content is rendered server-side
  • Faster development: Leverage Rails' view helpers and partials

JSON Approach - Possible but Not Ideal

While Stimulus.js can handle JSON responses, it goes against its core philosophy:

// This works but isn't the Stimulus way
export default class extends Controller {
  load() {
    fetch(this.urlValue)
      .then(response => response.json())
      .then(data => {
        // You'd need to manually create HTML from JSON
        this.element.innerHTML = this.buildHTML(data)
      })
  }

  buildHTML(data) {
    // Manual HTML construction - not recommended
    return data.items.map(item => 
      `<div class="item">${item.name}</div>`
    ).join('')
  }
}

Why JSON is less suitable:

  • Goes against Stimulus philosophy: Stimulus is designed to manipulate existing HTML, not create it
  • More complex: You need to handle HTML generation in JavaScript
  • State management issues: You'd need to manage state in JavaScript objects
  • Less maintainable: Template logic scattered between server and client

The Recommended Rails + Stimulus Pattern

The ideal approach combines:

  1. Turbo/Turbo Streams for page updates
  2. Stimulus for interactive behavior
  3. Server-rendered HTML for content
# Controller
def create
  @post = Post.new(post_params)
  
  respond_to do |format|
    if @post.save
      format.turbo_stream  # Returns HTML fragment
    else
      format.html { render :new, status: :unprocessable_entity }
    end
  end
end
<!-- _post.html.erb partial -->
<div data-controller="post" data-post-id-value="<%= post.id %>">
  <h3><%= post.title %></h3>
  <button data-action="post#like">Like</button>
</div>
// Stimulus controller for behavior
export default class extends Controller {
  static values = { id: Number }
  
  like() {
    // Simple interaction logic
    fetch(`/posts/${this.idValue}/like`, { method: 'POST' })
      .then(response => response.text())
      .then(html => /* update UI */)
  }
}

When to Consider JSON

JSON might be appropriate if you:

  • Need complex client-side data manipulation
  • Are building a single-page application section
  • Have heavy computational requirements on the client
  • Need to integrate with external APIs that only provide JSON

But even then, consider whether a heavier framework like React might be more appropriate for that specific section.

Recommendation

Stick with HTML partials and server-rendered content. This approach:

  • Leverages Rails' strengths
  • Keeps your application simple and maintainable
  • Follows Stimulus.js design principles
  • Provides better performance and SEO
  • Allows for progressive enhancement

Stimulus.js shines when it's enhancing server-rendered HTML with interactive behavior, not when it's trying to be a full client-side rendering framework.

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