Tabs
UI::TabsTabbed panels with keyboard navigation.
# VelvetKit
## Tabs (`UI::Tabs`)
Tabbed panels with keyboard navigation.
Add it: `bin/rails generate velvetkit:add tabs`
Also adds: `icon`
Stimulus: `ui--tabs`
### Arguments
```ruby
UI::Tabs.new(default_value:, variant: :line, size: :default, class: nil, **html_attrs)
```
Slots: `with_panel`, `with_trigger`, `with_leading_icon`
### Example: Default (Line)
```erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(default_value: "account")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "account") { "Account" } %>
<% list.with_trigger(value: "password") { "Password" } %>
<% list.with_trigger(value: "team") { "Team" } %>
<% list.with_trigger(value: "billing", disabled: true) { "Billing" } %>
<% end %>
<% tabs.with_panel(value: "account") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Manage your account settings and preferences.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Account content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "password") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Update your password and security settings.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Password content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "team") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Manage team members and permissions.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Team content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "billing") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">View and manage billing information.</p>
</div>
<% end %>
<% end %>
</div>
```
### Example: Pill Variant
```erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(variant: :pill, default_value: "general")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "general") { "General" } %>
<% list.with_trigger(value: "security") { "Security" } %>
<% list.with_trigger(value: "notifications") { "Notifications" } %>
<% end %>
<% tabs.with_panel(value: "general") do %>
<p class="text-sm text-muted-foreground">General settings for your application.</p>
<% end %>
<% tabs.with_panel(value: "security") do %>
<p class="text-sm text-muted-foreground">Security and privacy settings.</p>
<% end %>
<% tabs.with_panel(value: "notifications") do %>
<p class="text-sm text-muted-foreground">Notification preferences.</p>
<% end %>
<% end %>
</div>
```
### Example: With Icons
```erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(default_value: "profile")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "profile") do |trigger| %>
<% trigger.with_leading_icon(name: "user") %>
Profile
<% end %>
<% list.with_trigger(value: "security") do |trigger| %>
<% trigger.with_leading_icon(name: "lock") %>
Security
<% end %>
<% list.with_trigger(value: "settings") do |trigger| %>
<% trigger.with_leading_icon(name: "panel-left") %>
Settings
<% end %>
<% list.with_trigger(value: "verified", disabled: true) do |trigger| %>
<% trigger.with_leading_icon(name: "badge-check") %>
Verified
<% end %>
<% end %>
<% tabs.with_panel(value: "profile") do %>
<p class="text-sm text-muted-foreground">Your profile information.</p>
<% end %>
<% tabs.with_panel(value: "security") do %>
<p class="text-sm text-muted-foreground">Security settings.</p>
<% end %>
<% tabs.with_panel(value: "settings") do %>
<p class="text-sm text-muted-foreground">Application settings.</p>
<% end %>
<% tabs.with_panel(value: "verified") do %>
<p class="text-sm text-muted-foreground">Verification status.</p>
<% end %>
<% end %>
</div>
```
### Example: Settings Form
```erb
<div class="max-w-lg border rounded-lg p-6">
<h2 class="text-lg font-semibold mb-4">Settings</h2>
<%= render(UI::Tabs.new(variant: :line, default_value: "account")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "account") { "Account" } %>
<% list.with_trigger(value: "password") { "Password" } %>
<% list.with_trigger(value: "billing") { "Billing" } %>
<% end %>
<% tabs.with_panel(value: "account") do %>
<div class="space-y-4 mt-4">
<div>
<%= label_tag :name, "Name", class: "block text-sm font-medium mb-1" %>
<%= text_field_tag :name, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<div>
<%= label_tag :email, "Email", class: "block text-sm font-medium mb-1" %>
<%= email_field_tag :email, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<%= render(UI::Button.new) { "Save Changes" } %>
</div>
<% end %>
<% tabs.with_panel(value: "password") do %>
<div class="space-y-4 mt-4">
<div>
<%= label_tag :current, "Current Password", class: "block text-sm font-medium mb-1" %>
<%= password_field_tag :current, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<div>
<%= label_tag :new, "New Password", class: "block text-sm font-medium mb-1" %>
<%= password_field_tag :new, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<%= render(UI::Button.new) { "Update Password" } %>
</div>
<% end %>
<% tabs.with_panel(value: "billing") do %>
<div class="space-y-4 mt-4">
<p class="text-sm text-muted-foreground">Manage your billing information and subscription.</p>
<%= render(UI::Button.new(variant: :outline)) { "View Invoices" } %>
</div>
<% end %>
<% end %>
</div>
```
bin/rails generate velvetkit:add tabs
- Also adds
- Icon
- Stimulus
- ui--tabs
- Installs
- Nothing
Examples
Default (Line)
Manage your account settings and preferences.
Account content goes here.
Update your password and security settings.
Password content goes here.
Manage team members and permissions.
Team content goes here.
View and manage billing information.
default.html.erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(default_value: "account")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "account") { "Account" } %>
<% list.with_trigger(value: "password") { "Password" } %>
<% list.with_trigger(value: "team") { "Team" } %>
<% list.with_trigger(value: "billing", disabled: true) { "Billing" } %>
<% end %>
<% tabs.with_panel(value: "account") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Manage your account settings and preferences.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Account content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "password") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Update your password and security settings.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Password content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "team") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">Manage team members and permissions.</p>
<div class="p-4 border rounded-md">
<p class="text-sm">Team content goes here.</p>
</div>
</div>
<% end %>
<% tabs.with_panel(value: "billing") do %>
<div class="space-y-4">
<p class="text-sm text-muted-foreground">View and manage billing information.</p>
</div>
<% end %>
<% end %>
</div>
Pill Variant
General settings for your application.
Security and privacy settings.
Notification preferences.
pill_variant.html.erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(variant: :pill, default_value: "general")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "general") { "General" } %>
<% list.with_trigger(value: "security") { "Security" } %>
<% list.with_trigger(value: "notifications") { "Notifications" } %>
<% end %>
<% tabs.with_panel(value: "general") do %>
<p class="text-sm text-muted-foreground">General settings for your application.</p>
<% end %>
<% tabs.with_panel(value: "security") do %>
<p class="text-sm text-muted-foreground">Security and privacy settings.</p>
<% end %>
<% tabs.with_panel(value: "notifications") do %>
<p class="text-sm text-muted-foreground">Notification preferences.</p>
<% end %>
<% end %>
</div>
With Icons
Your profile information.
Security settings.
Application settings.
Verification status.
with_icons.html.erb
<div class="max-w-lg">
<%= render(UI::Tabs.new(default_value: "profile")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "profile") do |trigger| %>
<% trigger.with_leading_icon(name: "user") %>
Profile
<% end %>
<% list.with_trigger(value: "security") do |trigger| %>
<% trigger.with_leading_icon(name: "lock") %>
Security
<% end %>
<% list.with_trigger(value: "settings") do |trigger| %>
<% trigger.with_leading_icon(name: "panel-left") %>
Settings
<% end %>
<% list.with_trigger(value: "verified", disabled: true) do |trigger| %>
<% trigger.with_leading_icon(name: "badge-check") %>
Verified
<% end %>
<% end %>
<% tabs.with_panel(value: "profile") do %>
<p class="text-sm text-muted-foreground">Your profile information.</p>
<% end %>
<% tabs.with_panel(value: "security") do %>
<p class="text-sm text-muted-foreground">Security settings.</p>
<% end %>
<% tabs.with_panel(value: "settings") do %>
<p class="text-sm text-muted-foreground">Application settings.</p>
<% end %>
<% tabs.with_panel(value: "verified") do %>
<p class="text-sm text-muted-foreground">Verification status.</p>
<% end %>
<% end %>
</div>
Settings Form
Settings
Manage your billing information and subscription.
settings_form.html.erb
<div class="max-w-lg border rounded-lg p-6">
<h2 class="text-lg font-semibold mb-4">Settings</h2>
<%= render(UI::Tabs.new(variant: :line, default_value: "account")) do |tabs| %>
<% tabs.with_list do |list| %>
<% list.with_trigger(value: "account") { "Account" } %>
<% list.with_trigger(value: "password") { "Password" } %>
<% list.with_trigger(value: "billing") { "Billing" } %>
<% end %>
<% tabs.with_panel(value: "account") do %>
<div class="space-y-4 mt-4">
<div>
<%= label_tag :name, "Name", class: "block text-sm font-medium mb-1" %>
<%= text_field_tag :name, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<div>
<%= label_tag :email, "Email", class: "block text-sm font-medium mb-1" %>
<%= email_field_tag :email, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<%= render(UI::Button.new) { "Save Changes" } %>
</div>
<% end %>
<% tabs.with_panel(value: "password") do %>
<div class="space-y-4 mt-4">
<div>
<%= label_tag :current, "Current Password", class: "block text-sm font-medium mb-1" %>
<%= password_field_tag :current, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<div>
<%= label_tag :new, "New Password", class: "block text-sm font-medium mb-1" %>
<%= password_field_tag :new, "", class: "w-full px-3 py-2 border rounded-md text-sm" %>
</div>
<%= render(UI::Button.new) { "Update Password" } %>
</div>
<% end %>
<% tabs.with_panel(value: "billing") do %>
<div class="space-y-4 mt-4">
<p class="text-sm text-muted-foreground">Manage your billing information and subscription.</p>
<%= render(UI::Button.new(variant: :outline)) { "View Invoices" } %>
</div>
<% end %>
<% end %>
</div>
API
Arguments
UI::Tabs.new(default_value:, variant: :line, size: :default, class: nil, **html_attrs)
Slots:
with_panel
with_trigger
with_leading_icon