progressive-enhancement

javascript
import { Application } from "@hotwired/stimulus"
import FormSubmitController from "./controllers/form_submit_controller"

const application = Application.start()
application.debug = false

Disable submit button while Turbo form is submitting

rails hotwire stimulus
by codesnips 3 tabs
erb
<h1>Products</h1>

<%= form_with url: products_path, method: :get,
              data: { turbo_frame: "products_list", turbo_action: "advance" } do |f| %>
  <div class="filters">
    <%= f.text_field :q, value: params[:q], placeholder: "Search products" %>

Frame navigation that targets a specific frame via form_with

rails hotwire turbo
by codesnips 3 tabs
ruby
class ProductsController < ApplicationController
  before_action :set_product, only: %i[edit update]

  def index
    @products = Product.order(:name)
  end

Inline edit a table row with Turbo Frames

rails hotwire turbo
by codesnips 4 tabs
ruby
class Recipe < ApplicationRecord
  has_many :ingredients, inverse_of: :recipe, dependent: :destroy

  accepts_nested_attributes_for :ingredients,
    allow_destroy: true,
    reject_if: :all_blank

Add/remove nested fields with Stimulus (no cocoon)

rails hotwire stimulus
by codesnips 4 tabs
erb
<h1>Products</h1>

<%= link_to "New product", new_product_path, data: { turbo_frame: "modal" }, class: "btn" %>

<table id="products">
  <tbody>

Turbo Frame modal that renders server HTML

rails hotwire turbo
by codesnips 4 tabs
javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["input"]
  static values = { wait: { type: Number, default: 300 }, url: String }

Stimulus: debounced search that plays nicely with Turbo

rails stimulus hotwire
by codesnips 3 tabs
erb
<div class="orders-layout" data-controller="drawer">
  <table class="orders">
    <tbody>
      <% @orders.each do |order| %>
        <tr>
          <td><%= order.reference %></td>

Turbo Frames: inline “details drawer” without a SPA router

rails hotwire turbo
by codesnips 4 tabs
typescript
import { useCallback, useEffect, useRef, useState } from 'react';

export type CopyStatus = 'idle' | 'copied' | 'error';

function fallbackCopy(text: string): boolean {
  const textarea = document.createElement('textarea');

Frontend: copy-to-clipboard with fallback

frontend ux react
by codesnips 3 tabs
ruby
class SignupsController < ApplicationController
  def new
    @user = User.new
  end

  def create

Inline form validation feedback via Turbo Streams

rails hotwire turbo
by codesnips 4 tabs
erb
<%= turbo_frame_tag dom_id(contact) do %>
  <tr class="contact-row">
    <td><%= contact.name %></td>
    <td><%= contact.email %></td>
    <td><%= contact.role.titleize %></td>
    <td class="actions">

Turbo Frames: Inline edit that swaps form <-> row

rails turbo hotwire
by codesnips 3 tabs
ruby
Rails.application.routes.draw do
  concern :tabs do
    get :profile, on: :collection
    get :billing, on: :collection
    get :security, on: :collection
  end

Tabs UI using Turbo Frames (no client router)

rails hotwire turbo
by codesnips 4 tabs
ruby
class CommentsController < ApplicationController
  before_action :set_post

  def create
    @comment = @post.comments.build(comment_params)

Turbo Streams fallback to HTML for older clients

rails hotwire turbo-streams
by codesnips 4 tabs