Avatar stack
A labelled group of consistently sized avatars with overflow state.
- Source
app/components/nitro_kit/avatar_stack.rb- API
NitroKit::AvatarStack.new(label:, size:, max:) { |stack| stack.avatar; stack.overflow }
Sizes
The stack owns the size of every nested avatar and its overflow indicator.
Size scale
test/dummy/app/components/gallery/components/avatar_stack_page.rbGallery::Data.avatar_stack_sizes.each do |stack|
sample(stack.label, slug: stack.slug) do
render_stack(stack)
end
endOverflow counts
Small, large, and explicitly labelled overflow counts remain readable and announced.
Count scale
test/dummy/app/components/gallery/components/avatar_stack_page.rbsample("One more", slug: "one") do
render_overflow_stack(id: "gallery-avatar-stack-overflow-one", count: 1)
end
sample("Nine more", slug: "nine") do
render_overflow_stack(id: "gallery-avatar-stack-overflow-nine", count: 9)
end
sample("128 observers", slug: "large") do
render_overflow_stack(
id: "gallery-avatar-stack-overflow-large",
count: 128,
label: "128 additional deployment observers"
)
endAutomatic overflow
A max: count keeps the visible avatars bounded and derives the +N indicator.
Bounded participants
test/dummy/app/components/gallery/components/avatar_stack_page.rbrender NitroKit::AvatarStack.new(
id: "gallery-avatar-stack-max",
size: :md,
max: 3,
label: "Workspace participants"
) do |stack|
Gallery::Data.dense_members.first(6).each_with_index do |member, index|
stack.avatar(alt: member.name, id: "gallery-avatar-stack-max-#{index}")
end
endMixed identities
Image, generated fallback, long custom fallback, and overflow compose in one labelled group.
Deployment reviewers
test/dummy/app/components/gallery/components/avatar_stack_page.rbrender NitroKit::AvatarStack.new(
id: "gallery-avatar-stack-reviewers",
size: :lg,
label: "Deployment reviewers"
) do |stack|
stack.avatar(
src: "/gallery/avatars/grace.svg",
alt: "Grace Hopper",
fallback: "GH",
id: "gallery-avatar-stack-image"
)
stack.avatar(
alt: "Ada Lovelace",
id: "gallery-avatar-stack-generated"
)
stack.avatar(
alt: "Platform engineering team",
fallback: "TEAM",
id: "gallery-avatar-stack-long-fallback"
)
stack.overflow(3, label: "Three more deployment reviewers")
endComponent contract
Constructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::AvatarStack
- Constructor-specific options
- required
label: size: :md,max: nil,id: nil
- required
- Root and closed vocabulary
span[data-nk=avatar-stack][role=group]; sizesxs sm md lg- Compound contract
label:names the group;aria: { label: }raises.avatar(src:, alt:, fallback:, decorative:, loading:, decoding:, id:, html:, aria:, data:, desperately_need_a_class:)takes explicit keywords and inherits the stack size. Declarations are collected, so Nitro renders the avatars then the single overflow regardless of declaration order.max:bounds the visible avatars and derives a+Nindicator from the remainder; it cannot be combined with an explicitoverflow(count, label:), whose count must be positive and whose accessible label is owned bylabel:. The indicator carriesrole="img"; a derived one is named fromnitro_kit.avatar_stack.overflowwith the remaining count.
System rules for coding agents
Instructions for coding agents, repeated on every component page so one fetched page has enough context. Humans can usually skip this section.
test/dummy/app/components/gallery/agent_rules.rb
View agent instructions
- Nitro Kit 2.0 is a gem-owned, Phlex-only UI system for Rails. Render components directly:
render NitroKit::Button.new("Save", variant: :primary). - Compose Nitro components inside application-owned Phlex classes. Public initializers and declared slots are the component API; private methods are not.
- Public options are explicit keywords, and enumerated options are closed vocabularies. Invalid names or values raise
ArgumentError; this component's accepted options are in the contract above. - Pass native attributes through their typed boundary:
html:for HTML,aria:for ARIA, anddata:for application data.classandstyleare forbidden, including insidehtml:. - Nitro owns
NitroKit::Component::RESERVED_DATA_ATTRIBUTES:data-nk,data-slot,data-variant,data-size,data-nk-escape,data-enhanced,data-state,data-disabled,data-required,data-orientation,data-presentation,data-placement,data-layout,data-side,data-field-type,data-dir,data-gap,data-align,data-justify,data-wrap,data-cols,data-mode,data-key. Do not pass them throughdata:.data-action,data-controllerare additive and compose with Nitro behavior. - If an integration truly requires a class, use
desperately_need_a_class:. It requires a non-blank String and marks the exception withdata-nk-escape="class". - Every root emits
data-nk; owned parts emit component-qualifieddata-slotvalues such asfield-controlorcard-title. Select on those attributes, never on classes. - Customize components with documented
--nk-*custom properties in an application stylesheet. Variables beginning with--_nk-*are private component mechanics. - Use
NitroKit::FlexandNitroKit::Gridfor layout. Parents own external placement and available width; components own their intrinsic geometry. - Preserve native elements and accessibility semantics. State is exposed through native semantics and ARIA first, and through
data-statewhen styling or behavior also needs it.