Senren UI
Components / Api Key Field

Api Key Field

Stable Stimulus: senren--api-key-field

secret key display with reveal/copy/regenerate

Usage example #

Copy this ERB into a Rails view after installing the component. The snippet below is the same code used by the live preview above.

app/views/.../api_key_field_example.html.erb
<div class="w-full max-w-md">
  <%= render Senren::ApiKeyFieldComponent.new(
    value: "sk_live_1234abcd5678",
    label: "Production API key",
    reveal_label: "Reveal",
    hide_label: "Hide",
    copy_label: "Copy"
  ) %>
</div>

Install this component #

Copy the official component into your app

This component requires Stimulus. Keep --client so the controller is copied with the ViewComponent.

Terminal
bin/rails senren:add api_key_field --client

Create a custom component with the same conventions

Use this when you need an app-specific component that follows Senren's ViewComponent and Stimulus structure. --client is required for this behavior.

Terminal
bin/rails generate senren:component api_key_field --client

Dependencies are resolved by senren:add: input, button, clipboard.

At a glance #

Category Saas
Class name Senren::ApiKeyFieldComponent
Stimulus senren--api-key-field
Variants default
Depends on input, button, clipboard
Pairs with settings_section

Source #

app/components/senren/api_key_field_component.html.erb
<%= tag.div(**root_attrs("space-y-2", data: { controller: "senren--api-key-field", "senren--api-key-field-reveal-label-value": reveal_label, "senren--api-key-field-hide-label-value": hide_label, "senren--api-key-field-copy-label-value": copy_label })) do %>
  <% if content? && value.blank? %>
    <%= content %>
  <% else %>
    <label class="block text-sm font-medium text-[hsl(var(--senren-foreground))]"><%= label %></label>
    <div class="flex flex-col gap-2 sm:flex-row">
      <input type="password" readonly value="<%= value %>" data-senren--api-key-field-target="input" class="h-10 min-w-0 flex-1 rounded-(--senren-radius) border border-[hsl(var(--senren-input))] bg-[hsl(var(--senren-muted)/0.35)] px-3 font-mono text-sm text-[hsl(var(--senren-foreground))] outline-none focus:ring-2 focus:ring-[hsl(var(--senren-ring))]">
      <button type="button" data-senren--api-key-field-target="revealButton" data-action="click->senren--api-key-field#toggle" class="inline-flex h-10 cursor-pointer items-center justify-center rounded-(--senren-radius) border border-[hsl(var(--senren-border))] px-3 text-sm font-medium hover:bg-[hsl(var(--senren-accent))]"><%= reveal_label %></button>
      <button type="button" data-action="click->senren--api-key-field#copy" class="inline-flex h-10 cursor-pointer items-center justify-center rounded-(--senren-radius) bg-[hsl(var(--senren-primary))] px-3 text-sm font-medium text-[hsl(var(--senren-primary-foreground))] hover:opacity-90"><%= copy_label %></button>
    </div>
    <span class="sr-only" aria-live="polite" data-senren--api-key-field-target="status"></span>
  <% end %>
<% end %>
app/components/senren/api_key_field_component.rb
# frozen_string_literal: true

module Senren
  class ApiKeyFieldComponent < BaseComponent
    VARIANTS = { default: '' }.freeze
    SIZES = { md: '' }.freeze

    def initialize(value: nil, label: 'API key', reveal_label: 'Reveal', hide_label: 'Hide', copy_label: 'Copy',
                   class_name: nil, **html)
      super(variant: :default, size: :md, class_name: class_name, **html)
      @value = value
      @label = label
      @reveal_label = reveal_label
      @hide_label = hide_label
      @copy_label = copy_label
    end

    attr_reader :value, :label, :reveal_label, :hide_label, :copy_label
  end
end

AI agent rules #

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.