Billing portal · release 1842
Deployed by Grace Hopper on July 13, 2026 at 08:42 UTC.
Keyed disclosure sections with native buttons and visible state.
app/components/nitro_kit/accordion.rbNitroKit::Accordion.new(id:, mode:) { |accordion| accordion.item }Native details and summary elements work without JavaScript; single mode uses browser-native named grouping and keeps stable keyed IDs.
test/dummy/app/components/gallery/components/accordion_page.rbrender NitroKit::Accordion.new(id: "gallery-accordion-billing", mode: :single) do |accordion|
accordion.item(:invoices, title: "Where can I find invoices?", expanded: true) do
"Invoices are available from Billing settings."
end
accordion.item(:currency, title: "Can I change billing currency?") do
"Contact support before the next renewal date."
end
accordion.item(:legacy, title: "What happens to a legacy plan?") do
"Legacy plans retain their current limits until an owner chooses a new plan."
end
endSingle and multiple expansion modes remain useful from one disclosure through a dense set.
test/dummy/app/components/gallery/components/accordion_page.rbsample("One closed item", slug: "one-closed") do
render NitroKit::Accordion.new(id: "gallery-accordion-one", mode: :multiple) do |accordion|
accordion.item(:summary, title: "Workspace summary") do
"Mothership is on the Team plan with twelve active members."
end
end
end
sample("One open item", slug: "one-open") do
render NitroKit::Accordion.new(id: "gallery-accordion-one-open", mode: :single) do |accordion|
accordion.item(:summary, title: "Workspace summary", expanded: true) do
"Mothership is on the Team plan with twelve active members."
end
end
endtest/dummy/app/components/gallery/components/accordion_page.rbrender NitroKit::Accordion.new(id: "gallery-accordion-multiple", mode: :multiple) do |accordion|
accordion.item(:general, title: "General", expanded: true) do
"Workspace name, locale, and time zone."
end
accordion.item(:members, title: "Members and access", expanded: true) do
"Roles, pending invitations, and session policies."
end
accordion.item(:billing, title: "Billing") do
"Plan, payment method, and invoice history."
end
accordion.item(:advanced, title: "Advanced controls") do
"Advanced controls are managed by the organization owner."
end
endLong labels, long copy, nested markup, and many items use the same keyed declaration API.
Workspace records remain available throughout the current billing period. Exported audit events continue to use their original timestamps and actor identifiers.
test/dummy/app/components/gallery/components/accordion_page.rbrender NitroKit::Accordion.new(id: "gallery-accordion-pressure", mode: :multiple) do |accordion|
accordion.item(
:retention,
title: "How does workspace data retention change when a long-running organization changes plans?",
expanded: true
) do
p do
"Workspace records remain available throughout the current billing period. Exported audit events " \
"continue to use their original timestamps and actor identifiers."
end
ul do
li { "Active members keep their existing access until the renewal date." }
li { "Pending invitations can be revoked before the plan changes." }
li { "Invoice and audit exports remain available to workspace owners." }
end
end
accordion.item(:exports, title: "Exports") { "Exports are prepared as UTF-8 CSV files." }
accordion.item(:regions, title: "Data regions") { "The workspace currently uses the EU region." }
accordion.item(:sessions, title: "Active sessions") { "Owners can revoke individual sessions." }
accordion.item(:webhooks, title: "Webhook delivery") { "Failed deliveries retry with backoff." }
accordion.item(:legacy, title: "Legacy retention controls") do
"Legacy controls remain visible while owners plan their replacement."
end
endAn operational detail view composes cards, status, tables, and grouped actions inside panels.
Deployed by Grace Hopper on July 13, 2026 at 08:42 UTC.
| Check | Result |
|---|---|
| Application boot | Passed |
| Database connection | Passed |
| Queue latency | 42 ms |
EU region · protected branch · owner approval required
test/dummy/app/components/gallery/components/accordion_page.rbrender NitroKit::Accordion.new(id: "gallery-accordion-deployment", mode: :single) do |accordion|
accordion.item(:overview, title: "Deployment overview", expanded: true) do
render NitroKit::Card.new(id: "gallery-accordion-deployment-card") do |card|
card.title("Billing portal · release 1842", level: 3)
card.body do
render NitroKit::Badge.new(
"Operational",
id: "gallery-accordion-deployment-status",
color: :success,
size: :sm
)
p { "Deployed by Grace Hopper on July 13, 2026 at 08:42 UTC." }
end
card.footer do
render NitroKit::ButtonGroup.new(
id: "gallery-accordion-deployment-actions",
label: "Deployment actions"
) do |group|
group.button(
"View logs",
id: "gallery-accordion-deployment-logs",
href: "#deployment-logs",
size: :sm
)
group.button(
"Roll back",
id: "gallery-accordion-deployment-rollback",
variant: :destructive,
size: :sm
)
end
end
end
end
accordion.item(:checks, title: "Health checks") do
render_health_checks
end
accordion.item(:environment, title: "Environment and access") do
render NitroKit::Card.new(id: "gallery-accordion-environment-card") do |card|
card.title("Production environment", level: 3)
card.body do
p { "EU region · protected branch · owner approval required" }
end
card.footer do
render NitroKit::Badge.new(
"Protected",
id: "gallery-accordion-environment-status",
variant: :outline,
color: :info
)
end
end
end
endConstructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Accordion
id:mode: :multiplediv[data-nk=accordion]; modes multiple singleitem(key, title:, expanded: false) declarations. Each item renders native details and summary, so find-in-page and fragment navigation reveal matching closed content without a controller. Single mode gives every disclosure the same name and accepts at most one initially expanded item; multiple mode omits name. There is no disabled item or controller.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
render NitroKit::Button.new("Save", variant: :primary).ArgumentError; this component's accepted options are in the contract above.html: for HTML, aria: for ARIA, and data: for application data. class and style are forbidden, including inside html:.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 through data:. data-action, data-controller are additive and compose with Nitro behavior.desperately_need_a_class:. It requires a non-blank String and marks the exception with data-nk-escape="class".data-nk; owned parts emit component-qualified data-slot values such as field-control or card-title. Select on those attributes, never on classes.--nk-* custom properties in an application stylesheet. Variables beginning with --_nk-* are private component mechanics.NitroKit::Flex and NitroKit::Grid for layout. Parents own external placement and available width; components own their intrinsic geometry.data-state when styling or behavior also needs it.