ボタン
複数のバリアント(primary、secondary、ghost)とサイズ(sm、md、lg)を備えた汎用ボタンコンポーネント。 アイコン、ローディング状態に対応し、リンクやフォームボタンとしてレンダリングできます。
プレビュー & コード
_button.html.erb
<%#
Button Component (Classic)
Usage:
<%= render "components/button", label: "Click me" %>
<%= render "components/button", label: "Submit", variant: :primary, size: :lg %>
<%= render "components/button", label: "Cancel", variant: :ghost, href: "/" %>
%>
<%
variant ||= :primary
size ||= :md
href ||= nil
method ||= nil
disabled ||= false
icon ||= nil
icon_position ||= :leading
type ||= "button"
additional_class ||= defined?(binding.local_variable_get(:class)) ? binding.local_variable_get(:class) : ""
data ||= {}
base_classes = "inline-flex items-center justify-center gap-2 font-medium cursor-pointer transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 dark:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed"
variant_classes = case variant.to_sym
when :primary
"bg-slate-900 text-white hover:bg-slate-800 active:bg-slate-950 focus:ring-slate-900 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-white dark:active:bg-slate-200 dark:focus:ring-slate-300"
when :secondary
"bg-white text-slate-900 border border-slate-200 hover:bg-slate-50 hover:border-slate-300 active:bg-slate-100 focus:ring-slate-400 dark:bg-slate-800 dark:text-white dark:border-slate-700 dark:hover:bg-slate-700 dark:hover:border-slate-600 dark:active:bg-slate-900 dark:focus:ring-slate-500"
when :ghost
"text-slate-600 hover:text-slate-900 hover:bg-slate-100 active:bg-slate-200 focus:ring-slate-400 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-800 dark:active:bg-slate-700 dark:focus:ring-slate-500"
else
"bg-slate-900 text-white hover:bg-slate-800 active:bg-slate-950 focus:ring-slate-900 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-white dark:active:bg-slate-200 dark:focus:ring-slate-300"
end
size_classes = case size.to_sym
when :sm
"text-sm px-3 py-1.5 rounded-lg"
when :md
"text-sm px-4 py-2.5 rounded-lg"
when :lg
"text-base px-5 py-3 rounded-xl"
else
"text-sm px-4 py-2.5 rounded-lg"
end
all_classes = [base_classes, variant_classes, size_classes, additional_class].join(" ")
%>
<% if href.present? %>
<%= link_to href, class: all_classes, method: method, data: data do %>
<% if icon.present? && icon_position == :leading %>
<%= icon.html_safe %>
<% end %>
<%= label %>
<% if icon.present? && icon_position == :trailing %>
<%= icon.html_safe %>
<% end %>
<% end %>
<% else %>
<button type="<%= type %>" class="<%= all_classes %>" <%= "disabled" if disabled %> <% data.each do |key, value| %>data-<%= key %>="<%= value %>"<% end %>>
<% if icon.present? && icon_position == :leading %>
<%= icon.html_safe %>
<% end %>
<%= label %>
<% if icon.present? && icon_position == :trailing %>
<%= icon.html_safe %>
<% end %>
</button>
<% end %>
button_component.html.erb
<% if link? %>
<%= link_to @href, class: button_classes, method: @method, data: @data do %>
<% if @icon.present? && @icon_position == :leading %>
<%= @icon.html_safe %>
<% end %>
<%= @label %>
<% if @icon.present? && @icon_position == :trailing %>
<%= @icon.html_safe %>
<% end %>
<% end %>
<% else %>
<button type="<%= @type %>" class="<%= button_classes %>" <%= "disabled" if @disabled %> <% @data.each do |key, value| %>data-<%= key %>="<%= value %>"<% end %>>
<% if @icon.present? && @icon_position == :leading %>
<%= @icon.html_safe %>
<% end %>
<%= @label %>
<% if @icon.present? && @icon_position == :trailing %>
<%= @icon.html_safe %>
<% end %>
</button>
<% end %>
button_component.rb
# frozen_string_literal: true
class ButtonComponent < ViewComponent::Base
VARIANTS = %i[primary secondary ghost].freeze
SIZES = %i[sm md lg].freeze
attr_reader :label, :variant, :size, :href, :method, :disabled, :icon, :icon_position, :type, :data
def initialize(
label:,
variant: :primary,
size: :md,
href: nil,
method: nil,
disabled: false,
icon: nil,
icon_position: :leading,
type: "button",
data: {},
**extra_classes
)
@label = label
@variant = variant.to_sym
@size = size.to_sym
@href = href
@method = method
@disabled = disabled
@icon = icon
@icon_position = icon_position.to_sym
@type = type
@data = data
@extra_classes = extra_classes[:class] || ""
end
def button_classes
[ base_classes, variant_classes, size_classes, @extra_classes ].compact.join(" ")
end
def link?
@href.present?
end
private
def base_classes
"inline-flex items-center justify-center gap-2 font-medium cursor-pointer transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 dark:ring-offset-slate-900 disabled:opacity-50 disabled:cursor-not-allowed"
end
def variant_classes
case @variant
when :primary
"bg-slate-900 text-white hover:bg-slate-800 active:bg-slate-950 focus:ring-slate-900 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-white dark:active:bg-slate-200 dark:focus:ring-slate-300"
when :secondary
"bg-white text-slate-900 border border-slate-200 hover:bg-slate-50 hover:border-slate-300 active:bg-slate-100 focus:ring-slate-400 dark:bg-slate-800 dark:text-white dark:border-slate-700 dark:hover:bg-slate-700 dark:hover:border-slate-600 dark:active:bg-slate-900 dark:focus:ring-slate-500"
when :ghost
"text-slate-600 hover:text-slate-900 hover:bg-slate-100 active:bg-slate-200 focus:ring-slate-400 dark:text-slate-400 dark:hover:text-white dark:hover:bg-slate-800 dark:active:bg-slate-700 dark:focus:ring-slate-500"
else
"bg-slate-900 text-white hover:bg-slate-800 active:bg-slate-950 focus:ring-slate-900 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-white dark:active:bg-slate-200 dark:focus:ring-slate-300"
end
end
def size_classes
case @size
when :sm
"text-sm px-3 py-1.5 rounded-lg"
when :md
"text-sm px-4 py-2.5 rounded-lg"
when :lg
"text-base px-5 py-3 rounded-xl"
else
"text-sm px-4 py-2.5 rounded-lg"
end
end
end
変更履歴
- Initial release with primary, secondary, and ghost variants
- Three size options: sm, md (default), lg
- Icon support with leading/trailing positions
- Link and button rendering modes
この無料コンポーネントを気に入りましたか?一回のお支払いで全78コンポーネントを入手できます。
すべてのコンポーネントを取得