Components
Tabs
Theme
Hound
Framework
Tailwind CSS
Quicklinks
Quickly navigate to different tab patterns below
Tabs
Simple
Some activities...
Account information...
Billing information...
Team information...
<div data-controller="tabs"
data-tabs-active-tab="border-b border-indigo-600 inline-block bg-white text-indigo-600 dark:bg-slate-700 dark:text-white dark:border-indigo-400 rounded-t"
>
<div class="border-slate-200 border-b text-slate-600 dark:text-slate-100 dark:border-slate-600 font-medium text-sm">
<nav role="navigation" class="-mb-px">
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 border-b border-indigo-600 inline-block bg-white whitespace-nowrap dark:bg-slate-900">Activity</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white dark:bg-slate-900 inline-block whitespace-nowrap">Account</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white dark:bg-slate-900 inline-block whitespace-nowrap">Billing</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white dark:bg-slate-900 inline-block whitespace-nowrap">Team</a>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
<div data-controller="tabs"
data-tabs-active-tab="border-b border-indigo-600 inline-block bg-white text-indigo-600 dark:bg-slate-700 dark:text-white dark:border-indigo-400 rounded-t">
<div class="border-slate-200 border-b text-slate-600 dark:text-slate-100 dark:border-slate-600 font-medium text-sm">
<nav role="navigation" class="-mb-px">
<%= link_to "Activity", "#", data: { action: "click-tabs#change", tabs_target: "tab" }, class: "py-3 px-4 border-b border-indigo-600 inline-block bg-white whitespace-nowrap dark:bg-slate-900" %>
<%= link_to "Account", "#", data: { action: "click-tabs#change", tabs_target: "tab"}, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900" %>
<%= link_to "Billing", "#", data: { action: "click-tabs#change", tabs_target: "tab"}, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900" %>
<%= link_to "Team", "#", data: { action: "click-tabs#change", tabs_target: "tab" }, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900" %>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
%div{"data-controller" => "tabs", "data-tabs-active-tab" => "border-b border-indigo-600 inline-block bg-white text-indigo-600 dark:bg-slate-700 dark:text-white dark:border-indigo-400 rounded-t"}
.border-slate-200.border-b.text-slate-600.font-medium.text-sm.dark:text-slate-100.dark:border-slate-600
%nav.-mb-px{role: "navigation"}
= link_to "Activity", "#", data: { action: "click-tabs#change", tabs_target: "tab" }, class: "py-3 px-4 border-b border-indigo-600 inline-block bg-white whitespace-nowrap dark:bg-slate-900"
= link_to "Account", "#", data: { action: "click-tabs#change", tabs_target: "tab"}, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900"
= link_to "Billing", "#", data: { action: "click-tabs#change", tabs_target: "tab"}, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900"
= link_to "Team", "#", data: { action: "click-tabs#change", tabs_target: "tab" }, class: "py-3 px-4 bg-white inline-block whitespace-nowrap dark:bg-slate-900"
.p-4{"data-tabs-target" => "panel"}
Some activities...
.hidden.p-4{"data-tabs-target" => "panel"}
Account information...
.hidden.p-4{"data-tabs-target" => "panel"}
Billing information...
.hidden.p-4{"data-tabs-target" => "panel"}
Team information...
// Credits to @excid3 and crew
// https://github.com/excid3/tailwindcss-stimulus-components/graphs/contributors
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['tab', 'panel']
connect() {
this.activeTabClasses = (this.data.get('activeTab') || 'active').split(' ')
this.inactiveTabClasses = (this.data.get('inactiveTab') || 'inactive').split(' ')
if (this.anchor) this.index = this.tabTargets.findIndex((tab) => tab.id === this.anchor)
this.showTab()
}
change(event) {
event.preventDefault()
// If target specifies an index, use that
if (event.currentTarget.dataset.index) {
this.index = event.currentTarget.dataset.index
// If target specifies an id, use that
} else if (event.currentTarget.dataset.id) {
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id)
// Otherwise, use the index of the current target
} else {
this.index = this.tabTargets.indexOf(event.currentTarget)
}
window.dispatchEvent(new CustomEvent('tsc:tab-change'))
}
showTab() {
this.tabTargets.forEach((tab, index) => {
const panel = this.panelTargets[index]
if (index === this.index) {
panel.classList.remove('hidden')
tab.classList.remove(...this.inactiveTabClasses)
tab.classList.add(...this.activeTabClasses)
// Update URL with the tab ID if it has one
// This will be automatically selected on page load
if (tab.id) {
location.hash = tab.id
}
} else {
panel.classList.add('hidden')
tab.classList.remove(...this.activeTabClasses)
tab.classList.add(...this.inactiveTabClasses)
}
})
}
get index() {
return parseInt(this.data.get('index') || 0)
}
set index(value) {
this.data.set('index', (value >= 0 ? value : 0))
this.showTab()
}
get anchor() {
return (document.URL.split('#').length > 1) ? document.URL.split('#')[1] : null;
}
}
Tabs
Pills
Some activities...
Account information...
Billing information...
Team information...
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white"
data-tabs-inactive-tab="py-3 px-4 rounded-full inline-block dark:bg-slate-900 dark:text-slate-300">
<div class="text-slate-600 dark:text-slate-300">
<nav role="navigation" class="flex items-center space-x-1 font-medium text-sm">
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white">Activity</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-full inline-block dark:bg-slate-900">Account</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-full inline-block dark:bg-slate-900">Billing</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-full inline-block dark:bg-slate-900">Team</a>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white"
data-tabs-inactive-tab="py-3 px-4 rounded-full inline-block dark:bg-slate-900 dark:text-slate-300">
<div class="text-slate-600 dark:text-slate-300">
<nav role="navigation" class="flex items-center space-x-1 font-medium text-sm">
<%= link_to "Activity", "#", class: "py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Account", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Billing", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Team", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" } %>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
%div{"data-controller" => "tabs", "data-tabs-active-tab" => "py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white", "data-tabs-inactive-tab" => "py-3 px-4 rounded-full inline-block dark:bg-slate-900 dark:text-slate-300"}
.text-slate-600.dark:text-slate-300
%nav.flex.items-center.space-x-1.font-medium.text-sm{role: "navigation"}
= link_to "Activity", "#", class: "py-3 px-4 bg-indigo-50 inline-block rounded-full text-indigo-600 dark:bg-indigo-600 dark:text-white", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Account", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Billing", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Team", "#", class: "py-3 px-4 font-medium rounded", data: { action: "click->tabs#change", tabs_target: "tab" }
.p-4{"data-tabs-target" => "panel"}
Some activities...
.hidden.p-4{"data-tabs-target" => "panel"}
Account information...
.hidden.p-4{"data-tabs-target" => "panel"}
Billing information...
.hidden.p-4{"data-tabs-target" => "panel"}
Team information...
// Credit @excid3 and crew
// https://github.com/excid3/tailwindcss-stimulus-components/graphs/contributors
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['tab', 'panel']
connect() {
this.activeTabClasses = (this.data.get('activeTab') || 'active').split(' ')
this.inactiveTabClasses = (this.data.get('inactiveTab') || 'inactive').split(' ')
}
change(event) {
event.preventDefault()
// If target specifies an index, use that
if (event.currentTarget.dataset.index) {
this.index = event.currentTarget.dataset.index
// If target specifies an id, use that
} else if (event.currentTarget.dataset.id) {
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id)
// Otherwise, use the index of the current target
} else {
this.index = this.tabTargets.indexOf(event.currentTarget)
}
}
showTab() {
this.tabTargets.forEach((tab, index) => {
const panel = this.panelTargets[index]
if (index === this.index) {
panel.classList.remove('hidden')
tab.classList.remove(...this.inactiveTabClasses)
tab.classList.add(...this.activeTabClasses)
} else {
panel.classList.add('hidden')
tab.classList.remove(...this.activeTabClasses)
tab.classList.add(...this.inactiveTabClasses)
}
})
}
get index() {
return parseInt(this.data.get('index') || 0)
}
set index(value) {
this.data.set('index', (value >= 0 ? value : 0))
this.showTab()
}
}
Tabs
Rounded
Some activities...
Account information...
Billing information...
Team information...
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white"
data-tabs-inactive-tab="py-3 px-4 rounded-md inline-block dark:bg-slate-900 dark:text-slate-300">
<div>
<nav role="navigation" class="flex items-center text-gray-600 space-x-1 font-medium text-sm">
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white">Activity</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900">Account</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900">Billing</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900">Team</a>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white"
data-tabs-inactive-tab="py-3 px-4 rounded-md inline-block dark:bg-slate-900 dark:text-slate-300">
<div>
<nav role="navigation" class="flex items-center text-gray-600 space-x-1 font-medium text-sm">
<%= link_to "Activity", "#", class: "py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Account", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Billing", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= link_to "Team", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" } %>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
%div{"data-controller" => "tabs", "data-tabs-active-tab" => "py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white", "data-tabs-inactive-tab" => "py-3 px-4 rounded-md inline-block dark:bg-slate-900 dark:text-slate-300"}
%div
%nav.flex.items-center.text-gray-600.space-x-1.font-medium.text-sm{role: "navigation"}
= link_to "Activity", "#", class: "py-3 px-4 bg-indigo-50 inline-block rounded-md text-indigo-600 dark:bg-indigo-600 dark:text-white", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Account", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Billing", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" }
= link_to "Team", "#", class: "py-3 px-4 font-medium rounded-md inline-block dark:bg-slate-900", data: { action: "click->tabs#change", tabs_target: "tab" }
.p-4{"data-tabs-target" => "panel"}
Some activities...
.hidden.p-4{"data-tabs-target" => "panel"}
Account information...
.hidden.p-4{"data-tabs-target" => "panel"}
Billing information...
.hidden.p-4{"data-tabs-target" => "panel"}
Team information...
// Credit @excid3 and crew
// https://github.com/excid3/tailwindcss-stimulus-components/graphs/contributors
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['tab', 'panel']
connect() {
this.activeTabClasses = (this.data.get('activeTab') || 'active').split(' ')
this.inactiveTabClasses = (this.data.get('inactiveTab') || 'inactive').split(' ')
}
change(event) {
event.preventDefault()
// If target specifies an index, use that
if (event.currentTarget.dataset.index) {
this.index = event.currentTarget.dataset.index
// If target specifies an id, use that
} else if (event.currentTarget.dataset.id) {
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id)
// Otherwise, use the index of the current target
} else {
this.index = this.tabTargets.indexOf(event.currentTarget)
}
}
showTab() {
this.tabTargets.forEach((tab, index) => {
const panel = this.panelTargets[index]
if (index === this.index) {
panel.classList.remove('hidden')
tab.classList.remove(...this.inactiveTabClasses)
tab.classList.add(...this.activeTabClasses)
} else {
panel.classList.add('hidden')
tab.classList.remove(...this.activeTabClasses)
tab.classList.add(...this.inactiveTabClasses)
}
})
}
get index() {
return parseInt(this.data.get('index') || 0)
}
set index(value) {
this.data.set('index', (value >= 0 ? value : 0))
this.showTab()
}
}
Tabs
With icons
Some activities...
Account information...
Billing information...
Team information...
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t"
data-tabs-inactive-tab="py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600">
<div class="border-slate-200 border-b text-slate-600 dark:text-slate-200 dark:border-slate-600 text-sm font-medium">
<nav role="navigation" class="-mb-px flex items-center flex-wrap">
<a href="#"
data-tabs-target="tab" data-action="click->tabs#change"
class="py-3 px-4 border-b border-indigo-500 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t">
<%= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5" %>
<span>Activity</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600">
<%= icon "user-circle", classes: "w-5 h-5" %>
<span>Account</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600">
<%= icon "credit-card", classes: "w-5 h-5" %>
<span>Billing</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600">
<%= icon "users", classes: "w-5 h-5" %>
<span>Team</span>
</a>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
<div
data-controller="tabs"
data-tabs-active-tab="py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t"
data-tabs-inactive-tab="py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600">
<div class="border-slate-200 border-b text-slate-600 dark:text-slate-200 dark:border-slate-600 text-sm font-medium">
<nav role="navigation" class="-mb-px flex items-center flex-wrap">
<%= link_to "#", class: "py-3 px-4 border-b border-indigo-500 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t", data: { tabs_target: "tab", action: "click->tabs#change" } do %>
<%= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5" %>
<span>Activity</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do %>
<%= icon "user-circle", classes: "w-5 h-5" %>
<span>Account</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do %>
<%= icon "credit-card", classes: "w-5 h-5" %>
<span>Billing</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do %>
<%= icon "users", classes: "w-5 h-5" %>
<span>Team</span>
<% end %>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
%div{"data-controller" => "tabs", "data-tabs-active-tab" => "py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t", "data-tabs-inactive-tab" => "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600"}
.border-slate-200.border-b.text-slate-600.dark:text-slate-200.dark:border-slate-600.text-sm.font-medium
%nav.-mb-px.flex.items-center.flex-wrap{role: "navigation"}
= link_to "#", class: "py-3 px-4 border-b border-indigo-500 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600 dark:bg-indigo-600/70 dark:text-white dark:border-indigo-600 rounded-t", data: { tabs_target: "tab", action: "click->tabs#change" } do
= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5"
%span Activity
= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do
= icon "user-circle", classes: "w-5 h-5"
%span Account
= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do
= icon "credit-card", classes: "w-5 h-5"
%span Billing
= link_to "#", class: "py-3 px-4 flex items-center space-x-3 whitespace-nowrap border-b bg-white dark:bg-slate-900 dark:border-slate-600", data: {tabs_target: "tab", action: "click->tabs#change" } do
= icon "users", classes: "w-5 h-5"
%span Team
.p-4{"data-tabs-target" => "panel"}
Some activities...
.hidden.p-4{"data-tabs-target" => "panel"}
Account information...
.hidden.p-4{"data-tabs-target" => "panel"}
Billing information...
.hidden.p-4{"data-tabs-target" => "panel"}
Team information...
// Credits to @excid3 and crew
// https://github.com/excid3/tailwindcss-stimulus-components/graphs/contributors
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['tab', 'panel']
connect() {
this.activeTabClasses = (this.data.get('activeTab') || 'active').split(' ')
this.inactiveTabClasses = (this.data.get('inactiveTab') || 'inactive').split(' ')
if (this.anchor) this.index = this.tabTargets.findIndex((tab) => tab.id === this.anchor)
this.showTab()
}
change(event) {
event.preventDefault()
// If target specifies an index, use that
if (event.currentTarget.dataset.index) {
this.index = event.currentTarget.dataset.index
// If target specifies an id, use that
} else if (event.currentTarget.dataset.id) {
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id)
// Otherwise, use the index of the current target
} else {
this.index = this.tabTargets.indexOf(event.currentTarget)
}
window.dispatchEvent(new CustomEvent('tsc:tab-change'))
}
showTab() {
this.tabTargets.forEach((tab, index) => {
const panel = this.panelTargets[index]
if (index === this.index) {
panel.classList.remove('hidden')
tab.classList.remove(...this.inactiveTabClasses)
tab.classList.add(...this.activeTabClasses)
// Update URL with the tab ID if it has one
// This will be automatically selected on page load
if (tab.id) {
location.hash = tab.id
}
} else {
panel.classList.add('hidden')
tab.classList.remove(...this.activeTabClasses)
tab.classList.add(...this.inactiveTabClasses)
}
})
}
get index() {
return parseInt(this.data.get('index') || 0)
}
set index(value) {
this.data.set('index', (value >= 0 ? value : 0))
this.showTab()
}
get anchor() {
return (document.URL.split('#').length > 1) ? document.URL.split('#')[1] : null;
}
}
Tabs
Dark
Some activities...
Account information...
Billing information...
Team information...
<div data-controller="tabs"
data-tabs-active-tab="py-3 px-4 border-b border-indigo-300 flex items-center space-x-3 whitespace-nowrap text-indigo-300"
data-tabs-inactive-tab="py-3 px-4 bg-slate-800 flex items-center space-x-3 whitespace-nowrap border-b border-slate-700 dark:bg-transparent"
>
<div class="border-slate-200 border-b text-slate-300 font-medium text-sm">
<nav role="navigation" class="-mb-px flex items-center flex-wrap">
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600">
<%= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5" %>
<span>Activity</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent">
<%= icon "user-circle", classes: "w-5 h-5" %>
<span>Account</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent">
<%= icon "credit-card", classes: "w-5 h-5" %>
<span>Billing</span>
</a>
<a href="#" data-tabs-target="tab" data-action="click->tabs#change" class="py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent">
<%= icon "users", classes: "w-5 h-5" %>
<span>Team</span>
</a>
</nav>
</div>
<div class="p-4 text-slate-600" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4 text-slate-600" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4 text-slate-600" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4 text-slate-600" data-tabs-target="panel">
Team information...
</div>
</div>
<div data-controller="tabs"
data-tabs-active-tab="py-3 px-4 border-b border-indigo-300 flex items-center space-x-3 whitespace-nowrap text-indigo-300"
data-tabs-inactive-tab="py-3 px-4 bg-slate-800 flex items-center space-x-3 whitespace-nowrap border-b border-slate-700 dark:bg-transparent"
>
<div class="border-slate-200 border-b text-slate-300 font-medium text-sm">
<nav role="navigation" class="-mb-px flex items-center flex-wrap">
<%= link_to "#", class: "py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600", data: { action: "click->tabs#change", tabs_target: "tab" } do %>
<%= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5" %>
<span>Activity</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= icon "user-circle", classes: "w-5 h-5" %>
<span>Account</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= icon "credit-card", classes: "w-5 h-5" %>
<span>Billing</span>
<% end %>
<%= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" } %>
<%= icon "users", classes: "w-5 h-5" %>
<span>Team</span>
<% end %>
</nav>
</div>
<div class="p-4" data-tabs-target="panel">
Some activities...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Account information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Billing information...
</div>
<div class="hidden p-4" data-tabs-target="panel">
Team information...
</div>
</div>
%div{"data-controller" => "tabs", "data-tabs-active-tab" => "py-3 px-4 border-b border-indigo-300 flex items-center space-x-3 whitespace-nowrap text-indigo-300", "data-tabs-inactive-tab" => "py-3 px-4 bg-slate-800 flex items-center space-x-3 whitespace-nowrap border-b border-slate-700 dark:bg-transparent"}
.border-slate-200.border-b.text-slate-300.font-medium.text-sm
%nav.-mb-px.flex.items-center.flex-wrap{role: "navigation"}
= link_to "#", class: "py-3 px-4 border-b border-indigo-600 flex items-center space-x-3 bg-white whitespace-nowrap text-indigo-600", data: { action: "click->tabs#change", tabs_target: "tab" }
= icon "chat-bubble-oval-left-ellipsis", classes: "w-5 h-5"
%span Activity
= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" }
= icon "user-circle", classes: "w-5 h-5"
%span Account
= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" }
= icon "credit-card", classes: "w-5 h-5"
%span Billing
= link_to "#", class: "py-3 px-4 bg-white flex items-center space-x-3 whitespace-nowrap border-b dark:bg-transparent", data: { action: "click->tabs#change", tabs_target: "tab" }
= icon "users", classes: "w-5 h-5"
%span Team
.p-4{"data-tabs-target" => "panel"}
Some activities...
.hidden.p-4{"data-tabs-target" => "panel"}
Account information...
.hidden.p-4{"data-tabs-target" => "panel"}
Billing information...
.hidden.p-4{"data-tabs-target" => "panel"}
Team information...
// Credits to @excid3 and crew
// https://github.com/excid3/tailwindcss-stimulus-components/graphs/contributors
import { Controller } from '@hotwired/stimulus'
export default class extends Controller {
static targets = ['tab', 'panel']
connect() {
this.activeTabClasses = (this.data.get('activeTab') || 'active').split(' ')
this.inactiveTabClasses = (this.data.get('inactiveTab') || 'inactive').split(' ')
if (this.anchor) this.index = this.tabTargets.findIndex((tab) => tab.id === this.anchor)
this.showTab()
}
change(event) {
event.preventDefault()
// If target specifies an index, use that
if (event.currentTarget.dataset.index) {
this.index = event.currentTarget.dataset.index
// If target specifies an id, use that
} else if (event.currentTarget.dataset.id) {
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id)
// Otherwise, use the index of the current target
} else {
this.index = this.tabTargets.indexOf(event.currentTarget)
}
window.dispatchEvent(new CustomEvent('tsc:tab-change'))
}
showTab() {
this.tabTargets.forEach((tab, index) => {
const panel = this.panelTargets[index]
if (index === this.index) {
panel.classList.remove('hidden')
tab.classList.remove(...this.inactiveTabClasses)
tab.classList.add(...this.activeTabClasses)
// Update URL with the tab ID if it has one
// This will be automatically selected on page load
if (tab.id) {
location.hash = tab.id
}
} else {
panel.classList.add('hidden')
tab.classList.remove(...this.activeTabClasses)
tab.classList.add(...this.inactiveTabClasses)
}
})
}
get index() {
return parseInt(this.data.get('index') || 0)
}
set index(value) {
this.data.set('index', (value >= 0 ? value : 0))
this.showTab()
}
get anchor() {
return (document.URL.split('#').length > 1) ? document.URL.split('#')[1] : null;
}
}