Packages
petal_components
0.9.1
4.7.0
4.6.2
4.6.1
4.6.0
4.5.0
4.4.0
4.3.0
4.2.1
4.2.0
4.1.2
4.1.1
4.1.0
4.0.12
4.0.11
4.0.10
4.0.6
4.0.5
4.0.4
4.0.3
4.0.1
3.2.2
3.2.1
3.2.0
3.1.0
3.0.2
3.0.1
3.0.0
2.9.3
2.9.2
retired
2.9.1
retired
2.9.0
retired
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.2
2.1.1
2.1.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.1
1.7.0
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.19.10
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
Shadcn-style Phoenix LiveView components that AI assistants can actually use. Pair with the MCP server so AI coding tools can inspect the real component API.
Current section
Files
Jump to
Current section
Files
lib/petal_components/tabs.ex
defmodule PetalComponents.Tabs do
use Phoenix.Component
import PetalComponents.Link
# prop class, :string
# prop underline, :boolean, default: false
# slot default
def tabs(assigns) do
assigns = assigns
|> assign_new(:underline, fn -> false end)
|> assign_new(:class, fn -> "" end)
~H"""
<div class={Enum.join([
"flex gap-x-8 gap-y-2",
(if @underline, do: "border-b border-gray-200 dark:border-gray-600", else: ""),
@class
], " ")}>
<%= render_slot(@inner_block) %>
</div>
"""
end
# prop class, :string
# prop label, :string
# prop link_type, :string, options: ["a", "live_patch", "live_redirect"]
# prop number, :integer
# prop underline, :boolean, default: false
# prop is_active, :boolean, default: false
# slot default
def tab(assigns) do
assigns = assigns
|> assign_new(:label, fn -> nil end)
|> assign_new(:class, fn -> "" end)
|> assign_new(:inner_block, fn -> nil end)
|> assign_new(:number, fn -> nil end)
|> assign_new(:link_type, fn -> "a" end)
|> assign_new(:is_active, fn -> false end)
|> assign_new(:underline, fn -> false end)
|> assign_new(:extra_attributes, fn ->
Map.drop(assigns, [
:class,
:inner_block,
:number,
:link_type,
:is_active,
:underline,
:label,
:__slot__,
:__changed__
])
end)
~H"""
<.link link_type={@link_type} label={@label} to={@to} class={get_tab_class(@is_active, @underline)} {@extra_attributes}>
<%= if @number do %>
<.render_label_or_slot {assigns} />
<span class={get_tab_number_class(@is_active, @underline)}>
<%= @number %>
</span>
<% else %>
<.render_label_or_slot {assigns} />
<% end %>
</.link>
"""
end
def render_label_or_slot(assigns) do
~H"""
<%= if @inner_block do %>
<%= render_slot(@inner_block) %>
<% else %>
<%= @label %>
<% end %>
"""
end
# Pill CSS
defp get_tab_class(is_active, false) do
base_classes =
"whitespace-nowrap px-3 py-2 flex font-medium items-center text-sm rounded-md"
active_classes =
if is_active,
do: "bg-primary-100 dark:bg-gray-800 text-primary-600",
else: "text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 dark:hover:bg-gray-800 hover:bg-gray-100"
Enum.join([base_classes, active_classes], " ")
end
# Underline CSS
defp get_tab_class(is_active, underline) do
base_classes =
"whitespace-nowrap flex items-center py-3 px-3 border-b-2 font-medium text-sm"
active_classes =
if is_active,
do: "border-primary-500 text-primary-600",
else: "border-transparent text-gray-500 dark:hover:text-gray-400 dark:hover:border-gray-400 hover:text-gray-600"
underline_classes =
if is_active && underline,
do: "",
else: "hover:border-gray-300"
Enum.join([base_classes, active_classes, underline_classes], " ")
end
# Underline
defp get_tab_number_class(is_active, true = underline) do
base_classes =
"whitespace-nowrap ml-2 py-0.5 px-2 rounded-full text-xs font-normal"
active_classes =
if is_active,
do: "bg-primary-100 text-primary-600",
else: "bg-gray-100 text-gray-500"
underline_classes =
if underline && is_active,
do: "bg-primary-100 dark:bg-primary-600 text-primary-600 dark:text-white",
else: "bg-gray-100 dark:bg-gray-600 dark:text-white text-gray-500"
Enum.join([base_classes, active_classes, underline_classes], " ")
end
# Pill
defp get_tab_number_class(is_active, false) do
base_classes =
"whitespace-nowrap ml-2 py-0.5 px-2 rounded-full text-xs font-normal"
active_classes =
if is_active,
do: "bg-primary-600 text-white",
else: "bg-gray-500 dark:bg-gray-600 text-white"
Enum.join([base_classes, active_classes], " ")
end
end