Password input
UI::PasswordInputA password field with a show/hide toggle.
# VelvetKit
## Password input (`UI::PasswordInput`)
A password field with a show/hide toggle.
Add it: `bin/rails generate velvetkit:add password_input`
Also adds: `label`, `form_field`, `icon`, `spinner`, `button`, `input`, `input_group`
Stimulus: `ui--password-visibility`
### Arguments
```ruby
UI::PasswordInput.new(form: nil, field: nil, label: nil, hint: nil, required: false, disabled: false, error: nil, class: nil, **html_attrs)
```
### Notes
UI::PasswordInput — password field with a show/hide toggle.
Composes UI::InputGroup so the border, focus ring and disabled styling stay
identical to every other grouped input; the toggle is an inline-end addon
driven by the `ui--password-visibility` Stimulus controller.
Velvet::PasswordInput hardcoded a placeholder (shadowing the caller's) and
accepted `rounded:`/`full_width:`/`variant:`/`size:`/`mb:` that nothing read.
Those are gone. Its toggle was also dead — no controller was ever registered.
Usage:
<%= render(UI::PasswordInput.new(form: f, field: :password, required: true)) %>
<%= render(UI::PasswordInput.new(name: "user[password]")) %>
### Example: States
```erb
<%# Click the eye to toggle masking — driven by the ui--password-visibility controller. %>
<div class="flex max-w-sm flex-col gap-6">
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Default</span>
<%= render(UI::PasswordInput.new(name: "password_default", placeholder: "Enter your password")) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Required</span>
<%= render(UI::PasswordInput.new(name: "password_required", required: true)) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Error</span>
<%= render(UI::PasswordInput.new(name: "password_error", error: true)) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Disabled</span>
<%= render(UI::PasswordInput.new(name: "password_disabled", disabled: true)) %>
</div>
</div>
```
bin/rails generate velvetkit:add password_input
- Also adds
- Label Form field Icon Spinner Button Input Input group
- Stimulus
- ui--password-visibility
- Installs
- Nothing
Examples
States
Default
Required
Error
Disabled
states.html.erb
<%# Click the eye to toggle masking — driven by the ui--password-visibility controller. %>
<div class="flex max-w-sm flex-col gap-6">
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Default</span>
<%= render(UI::PasswordInput.new(name: "password_default", placeholder: "Enter your password")) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Required</span>
<%= render(UI::PasswordInput.new(name: "password_required", required: true)) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Error</span>
<%= render(UI::PasswordInput.new(name: "password_error", error: true)) %>
</div>
<div class="flex flex-col gap-2">
<span class="text-xs text-muted-foreground">Disabled</span>
<%= render(UI::PasswordInput.new(name: "password_disabled", disabled: true)) %>
</div>
</div>
API
Arguments
UI::PasswordInput.new(form: nil, field: nil, label: nil, hint: nil, required: false, disabled: false, error: nil, class: nil, **html_attrs)
Notes
UI::PasswordInput — password field with a show/hide toggle.
Composes UI::InputGroup so the border, focus ring and disabled styling stay
identical to every other grouped input; the toggle is an inline-end addon
driven by the `ui--password-visibility` Stimulus controller.
Velvet::PasswordInput hardcoded a placeholder (shadowing the caller's) and
accepted `rounded:`/`full_width:`/`variant:`/`size:`/`mb:` that nothing read.
Those are gone. Its toggle was also dead — no controller was ever registered.
Usage:
<%= render(UI::PasswordInput.new(form: f, field: :password, required: true)) %>
<%= render(UI::PasswordInput.new(name: "user[password]")) %>