Card
UI::CardA bordered container with header, content and footer.
# VelvetKit
## Card (`UI::Card`)
A bordered container with header, content and footer.
Add it: `bin/rails generate velvetkit:add card`
### Arguments
```ruby
UI::Card.new(class: nil, **html_attrs)
```
Slots: `with_header`, `with_card_content`, `with_footer`, `with_content`, `with_title`, `with_description`
### Example: Default (content only)
```erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_content do %>
<p class="text-sm text-muted-foreground">A simple card with only body content.</p>
<% end %>
<% end %>
</div>
```
### Example: With Header
```erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Notifications" } %>
<% header.with_description { "Configure how you receive notifications." } %>
<% end %>
<% card.with_content do %>
<p class="text-sm text-muted-foreground">Card with a header containing a title and description.</p>
<% end %>
<% end %>
</div>
```
### Example: With Footer
```erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_content do %>
<p class="text-sm text-muted-foreground">Card with body content and a footer containing actions.</p>
<% end %>
<% card.with_footer do %>
<div class="flex gap-2">
<%= render(UI::Button.new(variant: :primary, size: :sm)) { "Save" } %>
<%= render(UI::Button.new(variant: :outline, size: :sm)) { "Cancel" } %>
</div>
<% end %>
<% end %>
</div>
```
### Example: Complete (all sections)
```erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Team Members" } %>
<% header.with_description { "Manage your team and permissions." } %>
<% end %>
<% card.with_content do %>
<div class="space-y-3">
<div class="flex items-center gap-3">
<div class="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary">JD</div>
<div>
<p class="text-sm font-medium">John Doe</p>
<p class="text-xs text-muted-foreground">Admin</p>
</div>
</div>
<div class="flex items-center gap-3">
<div class="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary">AS</div>
<div>
<p class="text-sm font-medium">Alice Smith</p>
<p class="text-xs text-muted-foreground">Editor</p>
</div>
</div>
</div>
<% end %>
<% card.with_footer do %>
<div class="flex gap-2 w-full">
<%= render(UI::Button.new(variant: :outline, size: :sm, class: "w-full")) { "Invite Member" } %>
</div>
<% end %>
<% end %>
</div>
```
### Example: Settings Form
```erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Account Settings" } %>
<% header.with_description { "Update your account preferences." } %>
<% end %>
<% card.with_content do %>
<div class="space-y-4">
<div class="space-y-2">
<%= render(UI::Label.new(for: "name")) { "Display Name" } %>
<%= render(UI::Input.new(id: "name", placeholder: "Enter your name")) %>
</div>
<div class="space-y-2">
<%= render(UI::Label.new(for: "username")) { "Username" } %>
<%= render(UI::Input.new(id: "username", placeholder: "@username")) %>
</div>
</div>
<% end %>
<% card.with_footer do %>
<div class="flex gap-2">
<%= render(UI::Button.new(variant: :primary, size: :sm)) { "Save Changes" } %>
</div>
<% end %>
<% end %>
</div>
```
bin/rails generate velvetkit:add card
- Also adds
- Nothing else
- Stimulus
- None, it's server-rendered
- Installs
- Nothing
Examples
Default (content only)
A simple card with only body content.
default.html.erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_content do %>
<p class="text-sm text-muted-foreground">A simple card with only body content.</p>
<% end %>
<% end %>
</div>
With Header
Notifications
Configure how you receive notifications.
Card with a header containing a title and description.
with_header.html.erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Notifications" } %>
<% header.with_description { "Configure how you receive notifications." } %>
<% end %>
<% card.with_content do %>
<p class="text-sm text-muted-foreground">Card with a header containing a title and description.</p>
<% end %>
<% end %>
</div>
Complete (all sections)
Team Members
Manage your team and permissions.
JD
John Doe
Admin
AS
Alice Smith
Editor
complete.html.erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Team Members" } %>
<% header.with_description { "Manage your team and permissions." } %>
<% end %>
<% card.with_content do %>
<div class="space-y-3">
<div class="flex items-center gap-3">
<div class="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary">JD</div>
<div>
<p class="text-sm font-medium">John Doe</p>
<p class="text-xs text-muted-foreground">Admin</p>
</div>
</div>
<div class="flex items-center gap-3">
<div class="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-xs font-medium text-primary">AS</div>
<div>
<p class="text-sm font-medium">Alice Smith</p>
<p class="text-xs text-muted-foreground">Editor</p>
</div>
</div>
</div>
<% end %>
<% card.with_footer do %>
<div class="flex gap-2 w-full">
<%= render(UI::Button.new(variant: :outline, size: :sm, class: "w-full")) { "Invite Member" } %>
</div>
<% end %>
<% end %>
</div>
Settings Form
Account Settings
Update your account preferences.
settings_form.html.erb
<div class="max-w-sm">
<%= render(UI::Card.new) do |card| %>
<% card.with_header do |header| %>
<% header.with_title { "Account Settings" } %>
<% header.with_description { "Update your account preferences." } %>
<% end %>
<% card.with_content do %>
<div class="space-y-4">
<div class="space-y-2">
<%= render(UI::Label.new(for: "name")) { "Display Name" } %>
<%= render(UI::Input.new(id: "name", placeholder: "Enter your name")) %>
</div>
<div class="space-y-2">
<%= render(UI::Label.new(for: "username")) { "Username" } %>
<%= render(UI::Input.new(id: "username", placeholder: "@username")) %>
</div>
</div>
<% end %>
<% card.with_footer do %>
<div class="flex gap-2">
<%= render(UI::Button.new(variant: :primary, size: :sm)) { "Save Changes" } %>
</div>
<% end %>
<% end %>
</div>
API
Arguments
UI::Card.new(class: nil, **html_attrs)
Slots:
with_header
with_card_content
with_footer
with_content
with_title
with_description