# Senren UI

> A Rails UI library of ViewComponent, Stimulus and Tailwind components that are copied into your application rather than imported from a gem. You own the files after installation and edit them directly.

Install: `bundle add senren-ui` then `bin/rails generate senren:install`.
Add components: `bin/rails senren:add button card dialog`.

## Documentation

- [Introduction](https://senren-ui.dev/docs): what Senren is and when to reach for it
- [Installation](https://senren-ui.dev/docs/installation): generator, stylesheets, Stimulus wiring
- [Quickstart](https://senren-ui.dev/docs/quickstart): first component on a page
- [Theming](https://senren-ui.dev/docs/theming): the token set and the palette presets
- [Conventions](https://senren-ui.dev/docs/conventions): the rules components are written to
- [AI agents](https://senren-ui.dev/docs/ai-agents): the guide files the generator writes into your repo

## Components (64)

### Actions

Buttons, links, and clickable affordances.

- [Button](https://senren-ui.dev/components/button): primary action
  - Class: `Senren::ButtonComponent`
  - Variants: default, primary, secondary, destructive, ghost, link
  - Use for: primary action; secondary action; form submit; destructive action
  - Avoid: using destructive variant for non-destructive actions
  - Accessibility: Icon-only buttons must include aria-label. Use button for actions and anchor for navigation.
- [Link](https://senren-ui.dev/components/link): in-app navigation
  - Class: `Senren::LinkComponent`
  - Variants: default, muted, destructive
  - Use for: in-app navigation; external links
  - Avoid: triggering destructive actions via a link
  - Accessibility: Use real anchors for navigation never buttons.

### Forms

Form structure, labels, inputs, selects, validation surfaces.

- [Calendar](https://senren-ui.dev/components/calendar): date display and selection
  - Class: `Senren::CalendarComponent`
  - Variants: default
  - Use for: date display and selection
  - Avoid: time-only selection
  - Accessibility: grid with row/columnheader; arrow keys to navigate days.
  - Ships a Stimulus controller
- [Checkbox](https://senren-ui.dev/components/checkbox): boolean preferences
  - Class: `Senren::CheckboxComponent`
  - Variants: default
  - Use for: boolean preferences; multi-select via checkbox_group
  - Avoid: single-choice scenarios - use radio_button
  - Accessibility: Always pair with label or aria-label.
- [Checkbox Group](https://senren-ui.dev/components/checkbox_group): multi-select boolean groups
  - Class: `Senren::CheckboxGroupComponent`
  - Variants: default
  - Use for: multi-select boolean groups
  - Avoid: single-choice groups
  - Accessibility: Wrap in fieldset/legend.
- [Combobox](https://senren-ui.dev/components/combobox): searchable selects
  - Class: `Senren::ComboboxComponent`
  - Variants: default, error
  - Use for: searchable selects; large option lists
  - Avoid: short; fixed lists - use native_select
  - Accessibility: WAI-ARIA combobox pattern; aria-expanded; aria-activedescendant.
  - Ships a Stimulus controller
- [Date Picker](https://senren-ui.dev/components/date_picker): date input fields
  - Class: `Senren::DatePickerComponent`
  - Variants: default, error
  - Use for: date input fields
  - Avoid: date ranges - use a range component once added
  - Accessibility: Pair input with hidden calendar; provide manual typing fallback.
  - Ships a Stimulus controller
- [Form](https://senren-ui.dev/components/form): Rails form_with wrappers
  - Class: `Senren::FormComponent`
  - Variants: default
  - Use for: Rails form_with wrappers
  - Avoid: bypassing CSRF or Rails form helpers
  - Accessibility: Group related fields with fieldset/legend; show errors next to fields.
- [Input](https://senren-ui.dev/components/input): text
  - Class: `Senren::InputComponent`
  - Variants: default, error
  - Use for: text; email; password; number; search; url
  - Avoid: storing structured data in a single text input
  - Accessibility: Pair with label; use aria-invalid and aria-describedby on errors.
- [Label](https://senren-ui.dev/components/label): labeling form controls
  - Class: `Senren::LabelComponent`
  - Variants: default, required
  - Use for: labeling form controls
  - Avoid: using placeholder as the only label
  - Accessibility: Always associate via for=field-id.
- [Masked Input](https://senren-ui.dev/components/masked_input): phone
  - Class: `Senren::MaskedInputComponent`
  - Variants: default, error
  - Use for: phone; postal code; credit card; custom formats
  - Avoid: free text fields - use input
  - Accessibility: Always include a description of expected format.
  - Ships a Stimulus controller
- [Native Select](https://senren-ui.dev/components/native_select): short option lists
  - Class: `Senren::NativeSelectComponent`
  - Variants: default, error
  - Use for: short option lists; mobile-friendly selects
  - Avoid: long lists - prefer combobox
  - Accessibility: Pair with label; native option text must be meaningful.
- [Radio Button](https://senren-ui.dev/components/radio_button): single-choice option groups
  - Class: `Senren::RadioButtonComponent`
  - Variants: default
  - Use for: single-choice option groups
  - Avoid: multi-select - use checkbox_group
  - Accessibility: Group via fieldset/legend; share name attribute.
- [Select](https://senren-ui.dev/components/select): styled selects with custom option rendering
  - Class: `Senren::SelectComponent`
  - Variants: default, error
  - Use for: styled selects with custom option rendering
  - Avoid: very long lists - use combobox
  - Accessibility: aria-haspopup=listbox; arrow keys for navigation; type-ahead.
  - Ships a Stimulus controller
- [Switch](https://senren-ui.dev/components/switch): boolean toggles
  - Class: `Senren::SwitchComponent`
  - Variants: default
  - Use for: boolean toggles; settings
  - Avoid: actions that need confirmation - use button + dialog
  - Accessibility: role=switch with aria-checked.
- [Textarea](https://senren-ui.dev/components/textarea): multi-line text
  - Class: `Senren::TextareaComponent`
  - Variants: default, error
  - Use for: multi-line text
  - Avoid: rich-text editing - use rich_text_editor_lite
  - Accessibility: Pair with label; provide visible character counter for limits.

### Overlays

Dialogs, popovers, tooltips, sheets, menus.

- [Alert Dialog](https://senren-ui.dev/components/alert_dialog): destructive action confirmation
  - Class: `Senren::AlertDialogComponent`
  - Variants: default, destructive
  - Use for: destructive action confirmation; irreversible operations
  - Avoid: routine modal forms - use dialog
  - Accessibility: role=alertdialog with aria-labelledby. Confirm action receives initial focus only when non-destructive.
  - Ships a Stimulus controller
- [Context Menu](https://senren-ui.dev/components/context_menu): right-click actions on rows or canvases
  - Class: `Senren::ContextMenuComponent`
  - Variants: default
  - Use for: right-click actions on rows or canvases
  - Avoid: primary navigation; main page actions
  - Accessibility: Triggered by right-click and keyboard equivalent (Shift+F10). Must be reachable without a pointer.
  - Ships a Stimulus controller
- [Dialog](https://senren-ui.dev/components/dialog): confirmation modal
  - Class: `Senren::DialogComponent`
  - Variants: default
  - Use for: confirmation modal; short form modal
  - Avoid: long multi-step workflows; full page replacement
  - Accessibility: Must have a visible title. Must support Escape key close. Must trap focus and restore on close.
  - Ships a Stimulus controller
- [Dropdown Menu](https://senren-ui.dev/components/dropdown_menu): contextual actions on rows
  - Class: `Senren::DropdownMenuComponent`
  - Variants: default
  - Use for: contextual actions on rows; account menus
  - Avoid: primary navigation - use top_nav or sidebar
  - Accessibility: role=menu with role=menuitem children. Arrow keys to navigate; Escape to close; type-ahead optional.
  - Ships a Stimulus controller
- [Hover Card](https://senren-ui.dev/components/hover_card): user hover previews
  - Class: `Senren::HoverCardComponent`
  - Variants: default
  - Use for: user hover previews; link previews
  - Avoid: interactive forms - use popover or dialog
  - Accessibility: Provide keyboard activation; do not block touch users.
  - Ships a Stimulus controller
- [Popover](https://senren-ui.dev/components/popover): small contextual UI like filters or color pickers
  - Class: `Senren::PopoverComponent`
  - Variants: default
  - Use for: small contextual UI like filters or color pickers
  - Avoid: large content - use dialog or sheet
  - Accessibility: aria-expanded on trigger; manage focus on open.
  - Ships a Stimulus controller
- [Sheet](https://senren-ui.dev/components/sheet): side panels
  - Class: `Senren::SheetComponent`
  - Variants: right, left, top, bottom
  - Use for: side panels; mobile filters; edit panels
  - Avoid: destructive confirmation - use alert_dialog
  - Accessibility: Trap focus when open. Escape to close. aria-modal=true while open.
  - Ships a Stimulus controller
- [Tooltip](https://senren-ui.dev/components/tooltip): supplementary hints on hover/focus
  - Class: `Senren::TooltipComponent`
  - Variants: default
  - Use for: supplementary hints on hover/focus
  - Avoid: storing required information only in tooltip
  - Accessibility: Use aria-describedby; never put critical info in tooltips alone. Keyboard focus must show the tooltip.
  - Ships a Stimulus controller

### Navigation

Tabs, breadcrumbs, sidebar, theme toggle, shortcut keys.

- [Accordion](https://senren-ui.dev/components/accordion): FAQ
  - Class: `Senren::AccordionComponent`
  - Variants: single, multiple
  - Use for: FAQ; collapsible content sections
  - Avoid: primary navigation
  - Accessibility: Buttons toggle aria-expanded; panels use aria-hidden.
  - Ships a Stimulus controller
- [Breadcrumb](https://senren-ui.dev/components/breadcrumb): hierarchical navigation context
  - Class: `Senren::BreadcrumbComponent`
  - Variants: default
  - Use for: hierarchical navigation context
  - Avoid: non-hierarchical pages
  - Accessibility: aria-label="Breadcrumb"; mark current page with aria-current=page.
- [Collapsible](https://senren-ui.dev/components/collapsible): single show/hide toggles
  - Class: `Senren::CollapsibleComponent`
  - Variants: default
  - Use for: single show/hide toggles
  - Avoid: groups - use accordion
  - Accessibility: aria-expanded on trigger; aria-controls on panel.
  - Ships a Stimulus controller
- [Shortcut Key](https://senren-ui.dev/components/shortcut_key): displaying keyboard shortcuts in tooltips and menus
  - Class: `Senren::ShortcutKeyComponent`
  - Variants: default
  - Use for: displaying keyboard shortcuts in tooltips and menus
  - Avoid: as a button - shortcut_key is presentational
  - Accessibility: Use kbd elements; avoid relying on key visuals alone for instructions.
- [Sidebar](https://senren-ui.dev/components/sidebar): primary app navigation in dashboards
  - Class: `Senren::SidebarComponent`
  - Variants: default, compact
  - Use for: primary app navigation in dashboards
  - Avoid: marketing sites - use top_nav
  - Accessibility: role=navigation with aria-label; collapsed state retains tab order.
  - Ships a Stimulus controller
- [Tabs](https://senren-ui.dev/components/tabs): switching between related views in the same context
  - Class: `Senren::TabsComponent`
  - Variants: default, underline
  - Use for: switching between related views in the same context
  - Avoid: non-related sections - use a separate page
  - Accessibility: role=tablist with arrow-key navigation and aria-controls.
  - Ships a Stimulus controller
- [Theme Toggle](https://senren-ui.dev/components/theme_toggle): light/dark/system theme switching
  - Class: `Senren::ThemeToggleComponent`
  - Variants: default
  - Use for: light/dark/system theme switching
  - Avoid: non-theme settings
  - Accessibility: Announce current theme via aria-pressed or aria-label.
  - Ships a Stimulus controller

### Layout

Cards, separators, app shells, page headers, aspect ratios.

- [Aspect Ratio](https://senren-ui.dev/components/aspect_ratio): media
  - Class: `Senren::AspectRatioComponent`
  - Variants: square, video, portrait, ultrawide
  - Use for: media; image placeholders; embeds
  - Avoid: forcing aspect on text content
  - Accessibility: Inner media must include alt or aria-label.
- [Card](https://senren-ui.dev/components/card): grouping related content
  - Class: `Senren::CardComponent`
  - Variants: default, muted, outline
  - Use for: grouping related content; dashboard widgets; list items
  - Avoid: nesting cards inside cards
  - Accessibility: Use heading inside header slot; landmark roles only when meaningful.
- [Separator](https://senren-ui.dev/components/separator): grouping content blocks
  - Class: `Senren::SeparatorComponent`
  - Variants: horizontal, vertical
  - Use for: grouping content blocks
  - Avoid: decorative-only use without semantics
  - Accessibility: role=separator with aria-orientation.
- [Typography](https://senren-ui.dev/components/typography): page titles
  - Class: `Senren::TypographyComponent`
  - Variants: h1, h2, h3, h4, p, lead, large, small, muted
  - Use for: page titles; body copy; captions
  - Avoid: styling without semantic tag matching
  - Accessibility: Heading levels must be sequential; do not skip levels.

### Data Display

Tables, badges, avatars, progress, skeletons, pagination.

- [Alert](https://senren-ui.dev/components/alert): form feedback
  - Class: `Senren::AlertComponent`
  - Variants: default, info, success, warning, destructive
  - Use for: form feedback; page-level notices
  - Avoid: transient toasts - use a toast component instead
  - Accessibility: role=alert for error states; role=status for non-urgent updates.
- [Avatar](https://senren-ui.dev/components/avatar): user thumbnail
  - Class: `Senren::AvatarComponent`
  - Variants: sm, md, lg
  - Use for: user thumbnail; team list; comments
  - Avoid: decorative-only without alt
  - Accessibility: alt text required; fallback to initials with role=img and aria-label.
- [Badge](https://senren-ui.dev/components/badge): status
  - Class: `Senren::BadgeComponent`
  - Variants: default, secondary, success, warning, destructive, outline
  - Use for: status; priority; counts; tags
  - Avoid: interactive actions disguised as badges
  - Accessibility: Provide sufficient color contrast; do not encode meaning by color alone.
- [Clipboard](https://senren-ui.dev/components/clipboard): copy to clipboard buttons
  - Class: `Senren::ClipboardComponent`
  - Variants: default
  - Use for: copy to clipboard buttons
  - Avoid: non-text content
  - Accessibility: Announce copy success via aria-live region.
  - Ships a Stimulus controller
- [Pagination](https://senren-ui.dev/components/pagination): paged lists and tables
  - Class: `Senren::PaginationComponent`
  - Variants: default
  - Use for: paged lists and tables
  - Avoid: infinite scroll feeds
  - Accessibility: aria-current=page on current; nav landmark with label.
- [Progress](https://senren-ui.dev/components/progress): task progress
  - Class: `Senren::ProgressComponent`
  - Variants: default, success, warning, destructive
  - Use for: task progress; file upload; loading bars
  - Avoid: decorative animation
  - Accessibility: role=progressbar with aria-valuenow/min/max.
- [Skeleton](https://senren-ui.dev/components/skeleton): loading placeholders
  - Class: `Senren::SkeletonComponent`
  - Variants: default, circle, text
  - Use for: loading placeholders
  - Avoid: permanent decoration
  - Accessibility: aria-hidden=true while loading; pair with aria-busy on parent.
- [Table](https://senren-ui.dev/components/table): tabular data display
  - Class: `Senren::TableComponent`
  - Variants: default, compact
  - Use for: tabular data display
  - Avoid: layout - use grid/flex
  - Accessibility: Use real th/scope; caption for table summary.

### SaaS Blocks

Composite blocks for SaaS apps - settings, billing, team, search, filters.

- [Activity Feed](https://senren-ui.dev/components/activity_feed): audit logs
  - Class: `Senren::ActivityFeedComponent`
  - Variants: default
  - Use for: audit logs; comment threads; change history
  - Avoid: transient notifications - use alert or toast
  - Accessibility: Use a list; each entry has a relative time element.
- [Api Key Field](https://senren-ui.dev/components/api_key_field): secret key display with reveal/copy/regenerate
  - Class: `Senren::ApiKeyFieldComponent`
  - Variants: default
  - Use for: secret key display with reveal/copy/regenerate
  - Avoid: storing secrets in plain text on the server side
  - Accessibility: Reveal/hide must be reachable by keyboard; copy via clipboard with announcement.
  - Ships a Stimulus controller
- [App Shell](https://senren-ui.dev/components/app_shell): SaaS dashboard layout root
  - Class: `Senren::AppShellComponent`
  - Variants: default, compact
  - Use for: SaaS dashboard layout root
  - Avoid: marketing pages
  - Accessibility: Provide skip-to-content link; main landmark for page body.
- [Billing Plan Card](https://senren-ui.dev/components/billing_plan_card): pricing page or billing settings
  - Class: `Senren::BillingPlanCardComponent`
  - Variants: default, current, recommended
  - Use for: pricing page or billing settings
  - Avoid: feature comparison tables - use table
  - Accessibility: Use heading; price and features must be readable.
- [Bulk Action Bar](https://senren-ui.dev/components/bulk_action_bar): acting on multiple selected rows
  - Class: `Senren::BulkActionBarComponent`
  - Variants: default
  - Use for: acting on multiple selected rows
  - Avoid: single-row actions - use dropdown_menu
  - Accessibility: Show count of selected items in an aria-live region.
- [Cart](https://senren-ui.dev/components/cart): cart summary panels
  - Class: `Senren::CartComponent`
  - Variants: default, flush
  - Use for: cart summary panels; checkout side panels; order review before payment
  - Avoid: persisting quantities; the controller is display-only and the server is authoritative; formatting currency in the component; pass price_cents and a formatted price
  - Accessibility: Quantity steppers are grouped with an accessible name per line. Subtotal is text, not an image, so it is announced on change.
  - Ships a Stimulus controller
- [Data Table](https://senren-ui.dev/components/data_table): sortable
  - Class: `Senren::DataTableComponent`
  - Variants: default
  - Use for: sortable; filterable record lists
  - Avoid: static layout grids
  - Accessibility: Inherits from table; columns must have th/scope.
  - Ships a Stimulus controller
- [Empty State](https://senren-ui.dev/components/empty_state): zero-result lists
  - Class: `Senren::EmptyStateComponent`
  - Variants: default, illustrated
  - Use for: zero-result lists; no-data dashboards
  - Avoid: error states - use alert
  - Accessibility: Provide a meaningful heading and a primary action.
- [Filter Bar](https://senren-ui.dev/components/filter_bar): list filters above tables
  - Class: `Senren::FilterBarComponent`
  - Variants: default
  - Use for: list filters above tables
  - Avoid: primary navigation
  - Accessibility: Filter controls are real form controls with labels.
- [Invite Member Dialog](https://senren-ui.dev/components/invite_member_dialog): team invitation flow
  - Class: `Senren::InviteMemberDialogComponent`
  - Variants: default
  - Use for: team invitation flow
  - Avoid: bulk imports - use a dedicated screen
  - Accessibility: Inherit dialog accessibility; validate email server-side.
  - Ships a Stimulus controller
- [Page Header](https://senren-ui.dev/components/page_header): titled page header with actions
  - Class: `Senren::PageHeaderComponent`
  - Variants: default
  - Use for: titled page header with actions
  - Avoid: stacking multiple page_headers per page
  - Accessibility: Use h1 for page title.
- [Product Card](https://senren-ui.dev/components/product_card): product listings
  - Class: `Senren::ProductCardComponent`
  - Variants: default, featured
  - Use for: product listings; catalogue grids; storefront search results
  - Avoid: carrying cart state; adding to a cart is a form submission the server owns
  - Accessibility: Image alt text repeats the product title; decorative placeholder is aria-hidden. Out of stock disables the submit button rather than hiding it.
- [Search Input](https://senren-ui.dev/components/search_input): search above lists or in headers
  - Class: `Senren::SearchInputComponent`
  - Variants: default
  - Use for: search above lists or in headers
  - Avoid: global navigation - use command
  - Accessibility: aria-label or visible label; type=search; submit on Enter.
- [Settings Section](https://senren-ui.dev/components/settings_section): grouped settings inside a settings page
  - Class: `Senren::SettingsSectionComponent`
  - Variants: default
  - Use for: grouped settings inside a settings page
  - Avoid: unrelated content blocks
  - Accessibility: Each section has a heading and consistent label/value layout.
- [Stat Card](https://senren-ui.dev/components/stat_card): dashboard KPI tiles
  - Class: `Senren::StatCardComponent`
  - Variants: default, success, warning, destructive
  - Use for: dashboard KPI tiles
  - Avoid: interactive widgets - use card with explicit controls
  - Accessibility: Avoid color-only meaning; include label and value text.
- [Team Member List](https://senren-ui.dev/components/team_member_list): team management pages
  - Class: `Senren::TeamMemberListComponent`
  - Variants: default
  - Use for: team management pages
  - Avoid: arbitrary user lists - compose with table or card
  - Accessibility: Use semantic list markup.
- [Top Nav](https://senren-ui.dev/components/top_nav): global header with brand and account menu
  - Class: `Senren::TopNavComponent`
  - Variants: default
  - Use for: global header with brand and account menu
  - Avoid: primary in-app navigation - use sidebar
  - Accessibility: role=banner; nav landmark with label.

### Rich Content

Editors, code blocks, carousels, command palettes.

- [Carousel](https://senren-ui.dev/components/carousel): media galleries
  - Class: `Senren::CarouselComponent`
  - Variants: default
  - Use for: media galleries; marketing highlights
  - Avoid: primary navigation; important content gating
  - Accessibility: Provide pause/prev/next controls; respect prefers-reduced-motion.
  - Ships a Stimulus controller
- [Codeblock](https://senren-ui.dev/components/codeblock): displaying code samples
  - Class: `Senren::CodeblockComponent`
  - Variants: default
  - Use for: displaying code samples
  - Avoid: running code - this is read-only display
  - Accessibility: Use pre/code; preserve whitespace.
- [Command](https://senren-ui.dev/components/command): command palettes
  - Class: `Senren::CommandComponent`
  - Variants: default
  - Use for: command palettes; quick search
  - Avoid: persistent navigation
  - Accessibility: aria-activedescendant for current option; type-ahead filtering.
  - Ships a Stimulus controller
- [Rich Text Editor Lite](https://senren-ui.dev/components/rich_text_editor_lite): light formatting (bold/italic/links/lists) only
  - Class: `Senren::RichTextEditorLiteComponent`
  - Variants: default
  - Use for: light formatting (bold/italic/links/lists) only
  - Avoid: tables; embeds; media - out of scope for v0.1
  - Accessibility: Toolbar buttons must have aria-label; use contenteditable role=textbox.
  - Ships a Stimulus controller
