Button to
UI::ButtonToA button that submits a one-off form, like Rails' button_to.
# VelvetKit
## Button to (`UI::ButtonTo`)
A button that submits a one-off form, like Rails' button_to.
Add it: `bin/rails generate velvetkit:add button_to`
Also adds: `icon`, `spinner`, `button`
### Arguments
```ruby
UI::ButtonTo.new(path, form_class: nil, **args)
```
### Notes
UI::ButtonTo — a UI::Button rendered inside a real form via Rails' `button_to`.
Use when the action is a non-GET request (sign-in with a provider, destroy,
any state change) rather than navigation. Inherits UI::Button's variants,
sizes and icon slots so the two stay visually identical.
Velvet::ButtonTo inherited Button's icon/loading slots but its template never
rendered them; this one does.
Usage:
<%= render(UI::ButtonTo.new(sign_out_path, method: :delete, variant: :outline)) do %>
Sign out
<% end %>
### Example: Variants
```erb
<div class="flex flex-wrap items-center gap-3">
<% %i[default destructive outline secondary ghost link].each do |v| %>
<%= render(UI::ButtonTo.new("#", variant: v)) { v.to_s.capitalize } %>
<% end %>
</div>
```
### Example: With Icon
```erb
<%# Icon slots render here, unlike the Velvet component this replaces. %>
<div class="flex flex-wrap items-center gap-3">
<%= render(UI::ButtonTo.new("#", variant: :outline)) do |button| %>
<% button.with_leading_icon(name: "mail") %>
Sign in with email
<% end %>
<%= render(UI::ButtonTo.new("#")) do |button| %>
<% button.with_trailing_icon(name: "arrow-right") %>
Continue
<% end %>
</div>
```
### Example: States
```erb
<div class="flex flex-wrap items-center gap-3">
<%= render(UI::ButtonTo.new("#")) { "Default" } %>
<%= render(UI::ButtonTo.new("#", loading: true)) { "Loading" } %>
<%= render(UI::ButtonTo.new("#", disabled: true)) { "Disabled" } %>
</div>
<div class="mt-6 max-w-xs">
<%= render(UI::ButtonTo.new("#", variant: :outline, full_width: true, form_class: "w-full")) { "Full width" } %>
</div>
```
bin/rails generate velvetkit:add button_to
- Stimulus
- None, it's server-rendered
- Installs
- Nothing
Examples
Variants
variants.html.erb
<div class="flex flex-wrap items-center gap-3">
<% %i[default destructive outline secondary ghost link].each do |v| %>
<%= render(UI::ButtonTo.new("#", variant: v)) { v.to_s.capitalize } %>
<% end %>
</div>
With Icon
with_icon.html.erb
<%# Icon slots render here, unlike the Velvet component this replaces. %>
<div class="flex flex-wrap items-center gap-3">
<%= render(UI::ButtonTo.new("#", variant: :outline)) do |button| %>
<% button.with_leading_icon(name: "mail") %>
Sign in with email
<% end %>
<%= render(UI::ButtonTo.new("#")) do |button| %>
<% button.with_trailing_icon(name: "arrow-right") %>
Continue
<% end %>
</div>
States
states.html.erb
<div class="flex flex-wrap items-center gap-3">
<%= render(UI::ButtonTo.new("#")) { "Default" } %>
<%= render(UI::ButtonTo.new("#", loading: true)) { "Loading" } %>
<%= render(UI::ButtonTo.new("#", disabled: true)) { "Disabled" } %>
</div>
<div class="mt-6 max-w-xs">
<%= render(UI::ButtonTo.new("#", variant: :outline, full_width: true, form_class: "w-full")) { "Full width" } %>
</div>
API
Arguments
UI::ButtonTo.new(path, form_class: nil, **args)
Notes
UI::ButtonTo — a UI::Button rendered inside a real form via Rails' `button_to`.
Use when the action is a non-GET request (sign-in with a provider, destroy,
any state change) rather than navigation. Inherits UI::Button's variants,
sizes and icon slots so the two stay visually identical.
Velvet::ButtonTo inherited Button's icon/loading slots but its template never
rendered them; this one does.
Usage:
<%= render(UI::ButtonTo.new(sign_out_path, method: :delete, variant: :outline)) do %>
Sign out
<% end %>