Specialized action buttons for common UI interaction patterns.
Exports four components:
close_button/1— X / dismiss button for modals, drawers, and cardsbadge_button/1— button with a notification count badge overlayconfirm_button/1— inline two-step confirmation (no popover)countdown_button/1— timer-locked button for OTP resend / rate limiting
Notes
close_buttonrenders an inline X SVG — does NOT use<.icon>component.badge_buttonusesattr :count, :any(not:integer) so thatnil(no badge) is valid without a compile-time type error.confirm_buttonputs@reston the root<div>, NOT on inner buttons, to avoid double-binding phx-click etc.countdown_buttonalways rendersdisabled={true}initially; thePhiaCountdownButtonhook removes the attribute when the timer expires.
Summary
Functions
Renders a button with a notification count badge overlaid in a corner.
Renders a dedicated close / dismiss button with an inline X SVG.
Renders an inline two-step confirmation button.
Renders a timer-locked button for OTP resend, rate-limit cooldowns, etc.
Functions
Renders a button with a notification count badge overlaid in a corner.
Set count={nil} or count={0} to hide the badge. Values exceeding
max_count are shown as "99+" (or the custom max + "+").
Example
<.badge_button count={@unread_count}>
<.icon name="bell" class="h-4 w-4" />
Notifications
</.badge_button>
<.badge_button count={3} badge_color={:primary} variant={:outline}>
Messages
</.badge_button>Attributes
count(:any) - Badge count — nil hides badge, 0 hides badge, > max_count shows 'max+'. Defaults tonil.max_count(:integer) - Maximum displayed count — exceeded values show as 'max+'. Defaults to99.badge_color(:atom) - Badge background color. Defaults to:destructive. Must be one of:destructive,:primary,:warning, or:success.badge_position(:atom) - Badge overlay position relative to the button. Defaults to:top_right. Must be one of:top_right,:top_left,:bottom_right, or:bottom_left.variant(:atom) - Defaults to:default. Must be one of:default,:destructive,:outline,:secondary, or:ghost.size(:atom) - Defaults to:default. Must be one of:sm,:default, or:lg.disabled(:boolean) - Defaults tofalse.loading(:boolean) - Defaults tofalse.class(:string) - Defaults tonil.- Global attributes are accepted.
Slots
inner_block(required) - Button content.
Renders a dedicated close / dismiss button with an inline X SVG.
Does NOT use the <.icon> component — the X is always rendered inline so
this component has zero external dependencies.
Example
<.close_button phx-click={JS.hide(to: "#modal")} />
<.close_button size={:lg} shape={:circle} label="Dismiss notification" />Attributes
size(:atom) - Button dimensions. Defaults to:default. Must be one of:xs,:sm,:default, or:lg.variant(:atom) - Visual style — :ghost (default), :outline, or :filled. Defaults to:ghost. Must be one of:ghost,:outline, or:filled.label(:string) - aria-label text for screen readers. Defaults to"Close".shape(:atom) - Corner radius. Defaults to:square. Must be one of:square, or:circle.disabled(:boolean) - Defaults tofalse.class(:string) - Defaults tonil.- Global attributes are accepted.
Renders an inline two-step confirmation button.
On first click, the button transforms inline into "Are you sure?" + Yes +
Cancel — no popover or modal required. Auto-resets after timeout ms.
@rest is forwarded to the wrapper <div> — NOT to inner buttons —
to avoid double-binding phx-click or other LiveView bindings.
Example
<.confirm_button
id="delete-account"
label="Delete account"
on_confirm="delete_account"
confirm_value={@user_id}
/>Attributes
id(:string) (required) - Unique DOM ID — required for the PhiaConfirmButton hook.label(:string) - Initial button label. Defaults to"Delete".confirm_label(:string) - Label on the Yes button in the confirmation state. Defaults to"Yes, delete".cancel_label(:string) - Label on the Cancel button. Defaults to"Cancel".on_confirm(:string) - LiveView event name sent on Yes click (phx-click). Defaults tonil.confirm_value(:string) - phx-value-confirm passed with the on_confirm event. Defaults tonil.variant(:atom) - Variant for the initial button. Defaults to:destructive. Must be one of:default,:destructive,:outline,:secondary, or:ghost.confirm_variant(:atom) - Variant for the Yes confirmation button. Defaults to:destructive. Must be one of:default,:destructive,:outline,:secondary, or:ghost.size(:atom) - Defaults to:default. Must be one of:sm,:default, or:lg.timeout(:integer) - Milliseconds before the confirmation state auto-resets. Defaults to3000.disabled(:boolean) - Defaults tofalse.class(:string) - Defaults tonil.- Global attributes are accepted. HTML attributes forwarded to the root <div>.
Renders a timer-locked button for OTP resend, rate-limit cooldowns, etc.
The button is always rendered with disabled={true} on the server side.
The PhiaCountdownButton hook removes disabled when the timer reaches
zero. data-user-disabled carries the disabled attr value so the hook
knows not to re-enable when the user explicitly disabled the button.
The counting_label string supports a {n} placeholder that the hook
replaces on each tick (e.g. "Resend in {n}s" → "Resend in 42s").
Example
<.countdown_button id="resend-otp" seconds={60} phx-click="resend_otp" />
<.countdown_button
id="retry-btn"
seconds={30}
label="Retry"
counting_label="Please wait {n}s"
variant={:default}
/>Attributes
id(:string) (required) - Unique DOM ID — required for the PhiaCountdownButton hook.seconds(:integer) - Countdown duration in seconds. Defaults to60.label(:string) - Label shown when the countdown ends and button is enabled. Defaults to"Resend".counting_label(:string) - Label shown during countdown — the hook replaces {n} with the remaining seconds. Defaults to"Resend in {n}s".variant(:atom) - Defaults to:outline. Must be one of:default,:destructive,:outline,:secondary,:ghost, or:link.size(:atom) - Defaults to:default. Must be one of:xs,:sm,:default, or:lg.auto_start(:boolean) - Start the countdown immediately on mount. Defaults totrue.disabled(:boolean) - When true, the hook will not re-enable the button after the countdown ends. Defaults tofalse.class(:string) - Defaults tonil.- Global attributes are accepted.