erb

erb
<%= form_with model: @post, url: preview_posts_path, data: { turbo_frame: 'preview' } do |f| %>
  <%= f.text_area :body, rows: 10, class: 'w-full rounded border p-2' %>
  <%= f.submit 'Preview', class: 'mt-2 rounded bg-gray-100 px-3 py-1' %>
<% end %>

<%= turbo_frame_tag 'preview' do %>

Inline markdown preview using Turbo Frames

rails hotwire turbo
by Henry Kim 2 tabs
erb
<div id="draft_status" class="text-sm text-gray-500"></div>

<%= form_with model: @draft,
              url: draft_path(@draft),
              method: :patch,
              data: { controller: 'autosave', turbo_stream: true } do |f| %>

Autosave drafts with Stimulus + Turbo (lightweight)

rails hotwire stimulus
by Henry Kim 2 tabs
erb
<div data-controller="nested-fields">
  <template data-nested-fields-target="template">
    <%= form.fields_for :links, Link.new, child_index: 'NEW_RECORD' do |lf| %>
      <div class="flex gap-2">
        <%= lf.text_field :url, class: 'flex-1 rounded border p-2' %>
        <%= lf.hidden_field :_destroy, value: '0', data: { nested_fields_target: 'destroy' } %>

Add/remove nested fields with Stimulus (no cocoon)

rails hotwire stimulus
by Henry Kim 2 tabs
erb
<!DOCTYPE html>
<html>
  <head>
    <title>Contacts</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

Turbo Frames modal: load, submit, then close via stream

rails turbo hotwire
by codesnips 4 tabs
erb
<div id="toasts" class="fixed right-4 top-4 z-50 space-y-2"></div>

Toast notifications delivered with Turbo Streams

rails hotwire turbo
by Henry Kim 2 tabs
erb
<%= turbo_stream.append 'messages' do %>
  <%= render @message %>
<% end %>

<turbo-stream action="scroll_into_view" target="<%= dom_id(@message) %>"></turbo-stream>

Scroll into view after append using a custom Turbo Stream action

rails hotwire turbo
by Henry Kim 2 tabs
ruby
class SupportMailbox < ApplicationMailbox
  def process
    ticket = Ticket.find_or_create_by!(message_id: mail.message_id) do |t|
      t.subject = mail.subject
      t.from_email = mail.from&.first
      t.body = mail.decoded

Action Mailbox: broadcast incoming emails into a feed

rails hotwire turbo
by Henry Kim 3 tabs
javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["container", "dialog"]

  connect() {

Accessible modal dialogs with Stimulus and ARIA

stimulus accessibility ux
by Jordan Lee 2 tabs
erb
<%= turbo_frame_tag 'quick_view' do %>
  <div class="text-gray-500">Select a post…</div>
<% end %>

<% @posts.each do |post| %>
  <%= link_to post.title, post_path(post), data: { turbo_frame: 'quick_view' }, class: 'block py-1 hover:underline' %>

Frame-powered inline “quick view” that falls back to full page

rails hotwire turbo
by Henry Kim 2 tabs
erb
<div class="post">
  <h1><%= @post.title %></h1>

  <%= turbo_frame_tag "post_#{@post.id}" do %>
    <div class="post-content">
      <%= simple_format @post.body %>

Turbo Frame for inline editing without page reloads

hotwire turbo turbo-frames
by Jordan Lee 2 tabs
javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["count", "button"]
  static values = {
    url: String,

Optimistic UI updates with Turbo Streams

hotwire turbo stimulus
by Jordan Lee 3 tabs
javascript
import { Controller } from "@hotwired/stimulus"
import consumer from "../channels/consumer"

export default class extends Controller {
  static values = { roomId: Number }

Typing indicator via ActionCable + Turbo Streams

rails hotwire turbo
by Henry Kim 3 tabs