erb

ruby
class Comment < ApplicationRecord
  belongs_to :post
  belongs_to :author, class_name: 'Member'

  after_create_commit -> { broadcast_prepend_later_to(post, target: dom_id(post, :comments)) }
end

Live comments with model broadcasts + turbo_stream_from

rails hotwire turbo
by Henry Kim 3 tabs
erb
<%# private stream: turbo signs the serialized record name %>
<%= turbo_stream_from current_user %>

<section class="notifications">
  <h1>Notifications</h1>

Turbo Streams + authorization: signed per-user stream name

rails turbo hotwire
by codesnips 3 tabs
erb
<%= form_with url: issues_path, method: :get, data: { turbo_frame: 'issue_results' } do |f| %>
  <%= f.select :status, options_for_select(%w[open closed], params[:status]), include_blank: 'Any' %>
  <%= f.submit 'Apply', class: 'ml-2 rounded bg-gray-100 px-3 py-1' %>
<% end %>

<%= turbo_frame_tag 'issue_results' do %>

Frame navigation that targets a specific frame via form_with

rails hotwire turbo
by Henry Kim 2 tabs
erb
<div data-controller="disclosure">
  <button type="button" data-action="disclosure#toggle" aria-expanded="false" class="font-medium">
    Advanced
  </button>
  <div data-disclosure-target="panel" class="mt-2 hidden">
    <%= render 'advanced_filters' %>

Collapse/expand UI with Stimulus that survives Turbo swaps

rails hotwire stimulus
by Henry Kim 2 tabs
erb
<%= link_to project.name, project_path(project), data: { turbo_preload: true }, class: 'font-medium hover:underline' %>

Speed up perceived performance with Turbo preload links

rails hotwire turbo
by Henry Kim 2 tabs
erb
<div class="layout">
  <ul class="product-list">
    <% @products.each do |product| %>
      <li class="product-row">
        <%= link_to product.name,
              product_path(product),

Turbo Frames: “details” panel that lazy-loads on click

rails turbo hotwire
by codesnips 4 tabs
ruby
class CommentsController < ApplicationController
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.build(comment_params.merge(author: current_member))

    if @comment.save

Action Text comment form that works inside a Turbo Frame

rails hotwire turbo
by Henry Kim 2 tabs
erb
<%= turbo_frame_tag dom_id(user) do %>
  <tr>
    <td><%= user.name %></td>
    <td><%= user.role %></td>
    <td>
      <%= link_to 'Edit', edit_user_path(user), data: { turbo_frame: dom_id(user) } %>

Inline edit a table row with Turbo Frames

rails hotwire turbo
by Henry Kim 2 tabs
erb
<div data-controller="toast" data-toast-timeout-value="2500" class="rounded bg-gray-900 px-3 py-2 text-white">
  <div class="flex items-start justify-between gap-3">
    <div><%= message %></div>
    <button type="button" data-action="toast#close">✕</button>
  </div>
</div>

Stimulus toast auto-dismiss for Turbo-appended notifications

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

export default class extends Controller {
  static targets = ["bar", "percent", "status"]
  static values = {
    current: { type: Number, default: 0 },

Progress indicators for long-running operations

hotwire stimulus actioncable
by Jordan Lee 3 tabs
javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["menu", "overlay", "toggle"]

  toggle() {

Mobile-first responsive navigation with Stimulus

stimulus responsive mobile
by Jordan Lee 2 tabs
erb
<%= turbo_stream.remove dom_id(@task) %>

<%= turbo_stream.append 'toasts' do %>
  <%= render 'shared/toast' do %>
    Deleted. <%= link_to 'Undo', restore_task_path(@task), data: { turbo_method: :post }, class: 'underline' %>
  <% end %>

Undo delete with a Turbo Stream “restore” action

rails hotwire turbo
by Henry Kim 2 tabs