0

In my Rails 7 app I've got CustomersController where inside there is show action with the corresponding show.slim view. Inside this view I want to have 2 tabs:

  • "Data", with text of "This is data page" - this tab should be active after user hits show.slim
  • "Customer Users", with text of "Here is the list of Customer Users".

When user hits show url (customer_path) he should be able to see Data tab as active and after click "Customer Users" he/she should not be redirected anyway but stays at the page and the text of "Here is the list of Customer Users" should be rendered. I want to use turbo-frame to control tabs switching, no extra JS needed. I'm using tailwindcss.

So what I did is that:

customers/show.slim:

div.tabs
  button.tab-button[data-turbo-frame="customer_data" data-turbo-frame-target="data"] Data
  button.tab-button[data-turbo-frame="customer_users" data-turbo-frame-target="users"] Customer Users

= turbo_frame_tag "data" do
  h1 Data

  p This is data page

= turbo_frame_tag "users" do
  h1 Customer Users

  p Here is the list of Customer Users

With some extra css:

.tab-button {
  @apply inline-block py-2 px-4 border-b-2 font-medium text-sm focus:outline-none transition duration-150 ease-in-out;
}

.tab-button.active {
  @apply border-indigo-500 text-gray-900;
}

.tab-button:hover:not(.active) {
  @apply border-indigo-500 text-gray-900;
}

.tabs {
  @apply border-b border-gray-200 px-4 flex justify-start;
}

Instead I'm getting this view:

enter image description here

Like I said, at the first glance I want to understand what should be done to make it work? It has to be turbo-frame because EOD I'll have few view components for that.

mr_muscle
  • 2,536
  • 18
  • 61

1 Answers1

1

Turbo works by making requests to the back-end, so if you wish to render tab contents in the same request, you would have to use javascript for the hiding & showing of the tabs.

If you do wish to use turbo, then you would have to change the way you approach this:

  1. Since only one tab can be open at once, you don't need two turbo frames. You should have only one.

customers/show.slim

div.tabs
  button.tab-button[data-turbo-frame="tab_content"] Data
  button.tab-button[data-turbo-frame="tab_content"] Customer Users

= turbo_frame_tag "tab_content"
  1. Create a controller action for each of the tabs

app/controllers/customer_tabs_controller.rb

class CustomerTabsController < ApplicationController
  def data
  end

  def customer_users
  end
end

routes.rb

Rails.application.routes.draw do
  # ...

  resource :customer_tab, only: [] do
    get :data
    get :customer_users
  end
end
  1. Add view templates for these actions, with a turbo_frame containing the tab content. When rendered, the previous contents of the frame will be replaced by contents here.

app/views/customer_tabs/data.html.erb

= turbo_frame_tag "tab_content" do
  h1 Data

  p This is data page

app/views/customer_tabs/customer_users.html.erb

= turbo_frame_tag "tab_content" do
  h1 Customer Users

  p Here is the list of Customer Users
  1. Then, you have to add the links to tab buttons so clicking them will render the appropriate content.

customers/show.slim

div.tabs
  / To avoid having to specify `method: :get`, `link_to` could be used
  = button_to "Data", data_customer_tab_path, class: "tab-button", method: :get, data: { turbo_frame: "tab_content" }
  = button_to "Customer Users", customer_users_customer_tab_path, class: "tab-button", method: :get, data: { turbo_frame: "tab_content" }

= turbo_frame_tag "tab_content"

Now, clicking the tabs will open the respective tab content. To have the first tab load automatically upon opening the page, you would have to use eager loading frames

customers/show.slim

div.tabs
  = button_to "Data", data_customer_tab_path, class: "tab-button", method: :get, data: { turbo_frame: "tab_content" }
  = button_to "Customer Users", customer_users_customer_tab_path, class: "tab-button", method: :get, data: { turbo_frame: "tab_content" }

/ Will make a request for the data tab immediately and display it.
= turbo_frame_tag "tab_content", src: data_customer_tab_path do
  / The content that will be shown before the request to `data_customer_tab_path` completes
  p Loading...

As