Input group
UI::InputGroupA text field with addons before or after it.
# VelvetKit
## Input group (`UI::InputGroup`)
A text field with addons before or after it.
Add it: `bin/rails generate velvetkit:add input_group`
Also adds: `icon`, `spinner`, `button`, `label`, `form_field`, `input`
### Arguments
```ruby
UI::InputGroup.new(class: nil, **html_attrs)
```
Slots: `with_addon`, `with_field`, `with_icon`, `with_icon_button`
### Notes
UI::InputGroup — wrapper that visually merges a UI::Input with one or more
Addon decorators (icons, text, icon-buttons). The wrapper owns the border and
focus ring; the inner Field strips its own so there's no double border.
The wrapper's focus ring inherits from UI::Base::FOCUS_RING (same as Button)
wrapped in has-[] selectors, so changes propagate automatically.
Usage:
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "you@example.com") %>
<% end %>
### Example: All Addons
```erb
<%# Gallery of all addon configurations %>
<div class="flex flex-col gap-4 max-w-sm">
<%# Icon prefix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "Email") %>
<% end %>
<%# Text prefix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { "https://" } %>
<%= g.with_field(placeholder: "yoursite.com") %>
<% end %>
<%# Icon suffix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_field(placeholder: "Search…") %>
<%= g.with_addon(align: "inline-end") { |a| a.with_icon(name: "search") } %>
<% end %>
<%# Both sides %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { "$" } %>
<%= g.with_field(type: :number, placeholder: "0.00") %>
<%= g.with_addon(align: "inline-end") { "USD" } %>
<% end %>
<%# Error state %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "Invalid email", error: true) %>
<% end %>
</div>
```
bin/rails generate velvetkit:add input_group
- Stimulus
- None, it's server-rendered
- Installs
- Nothing
Examples
All Addons
addons.html.erb
<%# Gallery of all addon configurations %>
<div class="flex flex-col gap-4 max-w-sm">
<%# Icon prefix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "Email") %>
<% end %>
<%# Text prefix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { "https://" } %>
<%= g.with_field(placeholder: "yoursite.com") %>
<% end %>
<%# Icon suffix %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_field(placeholder: "Search…") %>
<%= g.with_addon(align: "inline-end") { |a| a.with_icon(name: "search") } %>
<% end %>
<%# Both sides %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { "$" } %>
<%= g.with_field(type: :number, placeholder: "0.00") %>
<%= g.with_addon(align: "inline-end") { "USD" } %>
<% end %>
<%# Error state %>
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "Invalid email", error: true) %>
<% end %>
</div>
API
Arguments
UI::InputGroup.new(class: nil, **html_attrs)
Slots:
with_addon
with_field
with_icon
with_icon_button
Notes
UI::InputGroup — wrapper that visually merges a UI::Input with one or more
Addon decorators (icons, text, icon-buttons). The wrapper owns the border and
focus ring; the inner Field strips its own so there's no double border.
The wrapper's focus ring inherits from UI::Base::FOCUS_RING (same as Button)
wrapped in has-[] selectors, so changes propagate automatically.
Usage:
<%= render(UI::InputGroup.new) do |g| %>
<%= g.with_addon(align: "inline-start") { |a| a.with_icon(name: "mail") } %>
<%= g.with_field(type: :email, placeholder: "you@example.com") %>
<% end %>