Packages
noora
0.83.2
0.84.1
0.84.0
0.83.2
0.83.1
0.83.0
0.82.7
0.82.6
0.82.5
0.82.4
0.82.3
0.82.2
0.82.1
0.82.0
0.81.4
0.81.3
0.81.2
0.81.1
0.81.0
0.80.1
0.80.0
0.79.1
0.79.0
0.78.1
0.78.0
0.77.4
0.77.3
0.77.2
0.77.1
0.77.0
0.76.0
0.75.0
0.74.0
0.73.0
0.72.0
0.71.0
0.70.0
0.69.1
0.69.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.2
0.64.1
0.64.0
0.63.2
0.63.1
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.0
0.54.0
0.53.1
0.53.0
0.52.1
0.52.0
0.51.0
0.50.1
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.3
0.44.2
0.44.1
0.44.0
0.43.0
0.42.0
0.41.0
0.40.6
0.40.5
0.40.4
0.40.3
0.40.2
0.40.1
0.40.0
0.39.1
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.1
0.32.0
0.31.0
0.30.0
0.29.2
0.29.1
0.29.0
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
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.0
0.1.0
0.1.0-rc.2
0.1.0-rc.1
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
A component library for Phoenix LiveView applications
Current section
Files
Jump to
Current section
Files
lib/noora/button_dropdown.ex
defmodule Noora.ButtonDropdown do
@moduledoc """
A button with an attached dropdown menu, combining a primary action button with a dropdown trigger.
The component renders a button that has a main clickable area and a separate dropdown trigger area,
allowing users to perform a primary action or access additional options via a dropdown menu.
## Example
```elixir
<.button_dropdown id="actions-menu" label="Button" size="large">
<:icon_left><.chevron_left /></:icon_left>
<:icon_right><.chevron_right /></:icon_right>
<.dropdown_item label="Option 1" on_click="option_1" />
<.dropdown_item label="Option 2" on_click="option_2" />
</.button_dropdown>
```
"""
use Phoenix.Component
import Noora.Icon
import Noora.Utils
@button_sizes ~w(medium large)
def button_sizes, do: @button_sizes
attr(:id, :string, required: true, doc: "Unique identifier for the dropdown component")
attr(:label, :string, required: true, doc: "The label of the button")
attr(:size, :string,
values: @button_sizes,
default: "large",
doc: "Determines the overall size of the elements, including padding, font size, and other items"
)
attr(:disabled, :boolean, default: false, doc: "Whether the button dropdown is disabled")
attr(:on_open_change, :string, default: nil, doc: "Event handler for when the dropdown opens")
attr(:on_highlight_change, :string,
default: nil,
doc: "Event handler for when the highlighted option changes"
)
attr(:on_select, :string, default: nil, doc: "Event handler for when an option is selected")
attr(:on_escape_key_down, :string,
default: nil,
doc: "Event handler for when the escape key is pressed"
)
attr(:on_pointer_down_outside, :string,
default: nil,
doc: "Event handler for when the pointer is pressed outside the dropdown"
)
attr(:on_focus_outside, :string,
default: nil,
doc: "Function called when the focus is moved outside the component"
)
attr(:on_interact_outside, :string,
default: nil,
doc: "Function called when an interaction happens outside the component"
)
attr(:close_on_select, :boolean,
default: true,
doc: "Whether to close the dropdown when an item is selected"
)
attr(:align, :string,
values: ~w(start end),
default: "start",
doc: "Alignment of the dropdown menu relative to the button"
)
attr(:rest, :global, include: ~w(phx-click), doc: "Additional HTML attributes for the main button")
slot(:icon_left, doc: "Icon displayed on the left of the label")
slot(:icon_right, doc: "Icon displayed on the right of the label")
slot(:inner_block, doc: "Content to be rendered inside the dropdown menu")
def button_dropdown(assigns) do
~H"""
<.portal id={@id <> "-content-portal"} target={"#" <> @id <> "-content-target"}>
{render_slot(@inner_block)}
</.portal>
<div
id={@id}
class="noora-button-dropdown"
phx-hook="NooraDropdown"
phx-update="ignore"
data-size={@size}
data-loop-focus
data-typeahead
data-close-on-select={to_string(@close_on_select)}
data-on-open-change={@on_open_change}
data-on-highlight-change={@on_highlight_change}
data-on-select={@on_select}
data-on-escape-key-down={@on_escape_key_down}
data-on-pointer-down-outside={@on_pointer_down_outside}
data-on-focus-outside={@on_focus_outside}
data-on-interact-outside={@on_interact_outside}
data-align={@align}
>
<button id={@id <> "-button"} data-part="main-button" disabled={@disabled} type="button" {@rest}>
<div :if={has_slot_content?(@icon_left, assigns)} data-part="icon-left">
{render_slot(@icon_left)}
</div>
<span data-part="label">{@label}</span>
<div :if={has_slot_content?(@icon_right, assigns)} data-part="icon-right">
{render_slot(@icon_right)}
</div>
</button>
<button data-part="trigger" disabled={@disabled} type="button">
<div data-part="indicator">
<.chevron_down />
</div>
</button>
<div data-part="positioner">
<div class="noora-dropdown-content" data-part="content">
<div id={@id <> "-content-target"} data-part="items"></div>
</div>
</div>
</div>
"""
end
end