Tables with Hotwire
Interactive table components with Turbo Frames & Stimulus
Sortable Table
Click column headers to sort • Powered by Stimulus
| 
                     
                      Name
                      
                     
                   | 
                  
                     
                      Role
                      
                     
                   | 
                  
                     
                      Email
                      
                     
                   | 
                  Status | 
|---|---|---|---|
| John Doe | Admin | [email protected] | Active | 
| Jane Smith | Editor | [email protected] | Inactive | 
| Mike Johnson | Viewer | [email protected] | Pending | 
| Sarah Williams | Manager | [email protected] | Active | 
| David Brown | Admin | [email protected] | Inactive | 
<div data-controller="table">
  <table class="min-w-full divide-y divide-gray-200">
    <thead class="bg-gray-50">
      <tr>
        <th 
          class="px-6 py-3 cursor-pointer"
          data-action="click->table#sort"
          data-column="name"
        >
          <div class="flex items-center space-x-1">
            <span>Name</span>
            <svg data-table-target="sortIcon">...</svg>
          </div>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr data-table-target="row">
        <td data-sort-value="John Doe">John Doe</td>
      </tr>
    </tbody>
  </table>
</div>
        Searchable Table with Live Filter
Client-side instant search • Powered by Stimulus
| Name | Role | Status | |
|---|---|---|---|
| John Doe | [email protected] | Admin | Active | 
| Jane Smith | [email protected] | Editor | Inactive | 
| Mike Johnson | [email protected] | Viewer | Pending | 
| Sarah Williams | [email protected] | Manager | Active | 
| David Brown | [email protected] | Admin | Inactive | 
| Emily Davis | [email protected] | Editor | Pending | 
| Chris Wilson | [email protected] | Viewer | Active | 
| Lisa Anderson | [email protected] | Manager | Inactive | 
No results found
Try adjusting your search query.
<div data-controller="table">
  <input 
    type="text" 
    placeholder="Search..."
    data-action="input->table#search"
  >
  
  <table>
    <tbody>
      <tr data-table-target="row">
        <td>John Doe</td>
        <td>[email protected]</td>
      </tr>
    </tbody>
  </table>
  
  <div data-empty-state class="hidden">
    No results found
  </div>
</div>
        Bulk Actions & Row Selection
Select rows • Perform bulk operations • Powered by Stimulus
| Name | Role | Status | ||
|---|---|---|---|---|
| 
                         
                              JD
                             
                          John Doe 
                           | 
                      [email protected] | Admin | Active | |
| 
                         
                              JS
                             
                          Jane Smith 
                           | 
                      [email protected] | Editor | Inactive | |
| 
                         
                              MJ
                             
                          Mike Johnson 
                           | 
                      [email protected] | Viewer | Pending | |
| 
                         
                              SW
                             
                          Sarah Williams 
                           | 
                      [email protected] | Manager | Active | |
| 
                         
                              DB
                             
                          David Brown 
                           | 
                      [email protected] | Admin | Inactive | 
<div data-controller="table">
  <!-- Bulk Actions Bar -->
  <div data-table-target="bulkActions" class="hidden">
    <span data-count>0</span> items selected
    <button data-action="click->table#bulkExport">Export</button>
    <button data-action="click->table#bulkDelete">Delete</button>
  </div>
  <table>
    <thead>
      <tr>
        <th>
          <input 
            type="checkbox"
            data-table-target="checkbox selectAll"
            data-action="change->table#toggleAll"
          >
        </th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <tr data-id="1">
        <td>
          <input 
            type="checkbox"
            data-table-target="checkbox"
            data-action="change->table#toggleRow"
          >
        </td>
        <td>John Doe</td>
      </tr>
    </tbody>
  </table>
</div>
        Expandable Rows
Click to expand & show additional details • Powered by Stimulus
| Product | Price | Stock | Status | |
|---|---|---|---|---|
| Wireless Headphones | $299.99 | 145 | In Stock | |
| Laptop Stand | $49.99 | 3 | Low Stock | |
| USB-C Cable | $19.99 | 0 | Out of Stock | |
| Mechanical Keyboard | $159.99 | 87 | In Stock | |
| Wireless Mouse | $79.99 | 234 | In Stock | 
<div data-controller="table">
  <table>
    <tbody>
      <tr>
        <td>
          <button data-action="click->table#toggleExpand">
            <svg class="transition-transform">...</svg>
          </button>
        </td>
        <td>Product Name</td>
      </tr>
      <!-- Expandable Content -->
      <tr class="expandable-content hidden">
        <td colspan="5">
          Additional product details...
        </td>
      </tr>
    </tbody>
  </table>
</div>
        Inline Editing with Turbo Frames
Edit cells directly • Auto-save • No page reload
| User | Role | Status | Actions | |
|---|---|---|---|---|
| 
     
          JD
         
      John Doe 
       | 
  [email protected] | Admin | Active | Edit | 
| 
     
          JS
         
      Jane Smith 
       | 
  [email protected] | Editor | Inactive | Edit | 
| 
     
          MJ
         
      Mike Johnson 
       | 
  [email protected] | Viewer | Pending | Edit | 
| 
     
          SW
         
      Sarah Williams 
       | 
  [email protected] | Manager | Active | Edit | 
<table>
  <tbody>
    <%= turbo_frame_tag "user_1" do %>
      <tr>
        <td><%= form.text_field :name %></td>
        <td><%= form.text_field :email %></td>
        <td>
          <%= form.submit "Save", 
              data: { turbo_frame: "user_1" } %>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>
<!-- Controller -->
def inline_edit
  render turbo_stream: turbo_stream.replace(
    "user_#{params[:id]}",
    partial: "user_row",
    locals: { user: updated_user }
  )
end
  Live Search with Turbo Frames
Server-side filtering • Real-time results • Debounced requests
| Name | Role | Status | |
|---|---|---|---|
| 
             
                  JD
                 
              John Doe 
               | 
          [email protected] | Admin | Active | 
| 
             
                  JS
                 
              Jane Smith 
               | 
          [email protected] | Editor | Inactive | 
| 
             
                  MJ
                 
              Mike Johnson 
               | 
          [email protected] | Viewer | Pending | 
| 
             
                  SW
                 
              Sarah Williams 
               | 
          [email protected] | Manager | Active | 
| 
             
                  DB
                 
              David Brown 
               | 
          [email protected] | Admin | Inactive | 
| 
             
                  ED
                 
              Emily Davis 
               | 
          [email protected] | Editor | Pending | 
| 
             
                  CW
                 
              Chris Wilson 
               | 
          [email protected] | Viewer | Active | 
| 
             
                  LA
                 
              Lisa Anderson 
               | 
          [email protected] | Manager | Inactive | 
<%= turbo_frame_tag "search_results" do %>
  <%= form_with url: filter_path, 
      data: { 
        turbo_frame: "search_results",
        action: "input->debounce#search" 
      } do |f| %>
    <%= f.text_field :query %>
  <% end %>
  <table id="users_table">
    <!-- Table content -->
  </table>
<% end %>
<!-- Controller -->
def filter
  @users = User.where("name LIKE ?", "%#{params[:query]}%")
  
  render turbo_stream: turbo_stream.replace(
    "users_table",
    partial: "users_table",
    locals: { users: @users }
  )
end
  Pagination with Turbo Frames
Navigate pages • No full page reload • Smooth transitions
| Name | Role | Status | |
|---|---|---|---|
| 
             
                  JD
                 
              John Doe 
               | 
          [email protected] | Admin | Active | 
| 
             
                  JS
                 
              Jane Smith 
               | 
          [email protected] | Editor | Inactive | 
| 
             
                  MJ
                 
              Mike Johnson 
               | 
          [email protected] | Viewer | Pending | 
| 
             
                  SW
                 
              Sarah Williams 
               | 
          [email protected] | Manager | Active | 
| 
             
                  DB
                 
              David Brown 
               | 
          [email protected] | Admin | Inactive | 
Page 1 of 4
<%= turbo_frame_tag "paginated_users" do %>
  <table>
    <!-- Table content -->
  </table>
<% end %>
<%= turbo_frame_tag "pagination" do %>
  <div class="flex justify-between">
    <%= link_to "Previous", 
        paginate_path(page: @page - 1),
        data: { turbo_frame: "paginated_users" } %>
    <%= link_to "Next", 
        paginate_path(page: @page + 1),
        data: { turbo_frame: "paginated_users" } %>
  </div>
<% end %>
<!-- Controller -->
def paginate
  @users = User.page(params[:page])
  
  render turbo_stream: [
    turbo_stream.replace("paginated_users", 
      partial: "users_table"),
    turbo_stream.replace("pagination", 
      partial: "pagination")
  ]
end
  Lazy Loading Details with Turbo Frames
Click to load additional data • On-demand fetching • Loading states
| Transaction | Date | Amount | Details | 
|---|---|---|---|
| 
               Payment from Customer A 
              ID: 001 
             | 
            Jan 15, 2025 | +$1200.00 | 
               | 
          
| 
               | 
          |||
| 
               Subscription Renewal 
              ID: 002 
             | 
            Jan 16, 2025 | +$99.00 | 
               | 
          
| 
               | 
          |||
| 
               Refund to Customer B 
              ID: 003 
             | 
            Jan 17, 2025 | $350.00 | 
               | 
          
| 
               | 
          |||
| 
               Payment from Customer C 
              ID: 004 
             | 
            Jan 18, 2025 | +$2500.00 | 
               | 
          
| 
               | 
          |||
| 
               Service Fee 
              ID: 005 
             | 
            Jan 19, 2025 | $45.00 | 
               | 
          
| 
               | 
          |||
<table>
  <tbody>
    <tr>
      <td>Transaction Info</td>
      <td>
        <%= turbo_frame_tag "details_1" do %>
          <%= link_to "View Details", 
              details_path(1),
              data: { turbo_frame: "details_1" } %>
        <% end %>
      </td>
    </tr>
    <tr>
      <td colspan="4">
        <%= turbo_frame_tag "details_1" do %>
          <!-- Details loaded here -->
        <% end %>
      </td>
    </tr>
  </tbody>
</table>
<!-- Controller -->
def load_details
  @transaction = Transaction.find(params[:id])
  
  render partial: "transaction_details",
         locals: { transaction: @transaction }
end
  Responsive Mobile-Friendly Table
Adapts to small screens • Card layout on mobile • Powered by Tailwind
| Product | Category | Price | Stock | Status | Actions | 
|---|---|---|---|---|---|
| Wireless Headphones | Electronics | $299.99 | 145 | In Stock | Edit Delete | 
| Laptop Stand | Electronics | $49.99 | 3 | Low Stock | Edit Delete | 
| USB-C Cable | Electronics | $19.99 | 0 | Out of Stock | Edit Delete | 
| Mechanical Keyboard | Electronics | $159.99 | 87 | In Stock | Edit Delete | 
| Wireless Mouse | Electronics | $79.99 | 234 | In Stock | Edit Delete | 
<!-- Desktop Table View -->
<div class="hidden md:block">
  <table class="min-w-full">
    <thead>
      <tr>
        <th>Product</th>
        <th>Price</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Wireless Headphones</td>
        <td>$299.99</td>
        <td><a href="#">Edit</a></td>
      </tr>
    </tbody>
  </table>
</div>
<!-- Mobile Card View -->
<div class="md:hidden space-y-4">
  <div class="border rounded-lg p-4">
    <h3 class="font-semibold">Wireless Headphones</h3>
    <div class="grid grid-cols-2 gap-3 mt-3">
      <div>
        <p class="text-xs text-gray-500">Price</p>
        <p class="font-medium">$299.99</p>
      </div>
    </div>
    <div class="flex justify-end mt-3 pt-3 border-t">
      <a href="#">Edit</a>
    </div>
  </div>
</div>
  Advanced Filters with Turbo Frames
Multiple filter options • Real-time updates • Powered by Turbo
Showing 8 results
| User | Role | Status | Actions | |
|---|---|---|---|---|
| 
                   
                        JD
                       
                    John Doe 
                     | 
                [email protected] | Admin | Active | |
| 
                   
                        JS
                       
                    Jane Smith 
                     | 
                [email protected] | Editor | Inactive | |
| 
                   
                        MJ
                       
                    Mike Johnson 
                     | 
                [email protected] | Viewer | Pending | |
| 
                   
                        SW
                       
                    Sarah Williams 
                     | 
                [email protected] | Manager | Active | |
| 
                   
                        DB
                       
                    David Brown 
                     | 
                [email protected] | Admin | Inactive | |
| 
                   
                        ED
                       
                    Emily Davis 
                     | 
                [email protected] | Editor | Pending | |
| 
                   
                        CW
                       
                    Chris Wilson 
                     | 
                [email protected] | Viewer | Active | |
| 
                   
                        LA
                       
                    Lisa Anderson 
                     | 
                [email protected] | Manager | Inactive | 
No matching results
Try adjusting your filters or search terms.
<div data-controller="table">
  <!-- Filters -->
  <div class="mb-6 p-4 bg-gray-50 rounded-lg">
    <input 
      type="text" 
      data-action="input->table#search"
      placeholder="Search..."
    >
    
    <select data-action="change->table#search">
      <option value="">All Roles</option>
      <option value="admin">Admin</option>
    </select>
  </div>
  <!-- Results -->
  <table>
    <tbody>
      <tr data-table-target="row">
        <td>John Doe</td>
        <td>Admin</td>
      </tr>
    </tbody>
  </table>
  <!-- Empty State -->
  <div data-empty-state class="hidden">
    No matching results
  </div>
</div>