A labelled settings navigation beside one neutral content region with a Nitro-owned narrow stack.
app/components/nitro_kit/settings_layout.rbNitroKit::SettingsLayout.new { |layout| layout.navigation(label:) { ... }; layout.content { ... } }One labelled native navigation and one neutral content region form the complete contract.
test/dummy/app/components/gallery/blocks/settings_layout_page.rbrender NitroKit::SettingsLayout.new(id: "gallery-settings-layout-workspace") do |layout|
layout.navigation(label: "Workspace settings") do
render_navigation("workspace", current: :profile)
end
layout.content do
render NitroKit::Card.new(id: "gallery-settings-layout-profile-card") do |card|
card.title("Public profile", level: 4)
card.body do
render NitroKit::Field.new(
nil,
:name,
id: "gallery-settings-layout-profile-name",
name: "profile[name]",
value: "Ada Lovelace",
label: "Name"
)
end
card.footer do
render NitroKit::Button.new(
"Save profile",
id: "gallery-settings-layout-profile-save",
variant: :primary
)
end
end
end
endThe regions remain explicit with empty, single-surface, and dense caller-owned content.
test/dummy/app/components/gallery/blocks/settings_layout_page.rbsample("Empty content", slug: "empty") do
render NitroKit::SettingsLayout.new(id: "gallery-settings-layout-empty") do |layout|
layout.navigation(label: "Empty settings")
layout.content
end
end
sample("One surface", slug: "one") do
render NitroKit::SettingsLayout.new(id: "gallery-settings-layout-one") do |layout|
layout.navigation(label: "Account settings") do
render NitroKit::Button.new("Profile", href: "#profile")
end
layout.content do
render NitroKit::Alert.new(id: "gallery-settings-layout-one-alert") do |alert|
alert.title("Nothing needs attention")
alert.description("Your account settings are current.")
end
end
end
end
sample("Dense content", slug: "many") do
render NitroKit::SettingsLayout.new(id: "gallery-settings-layout-many") do |layout|
layout.navigation(label: "Operations settings") do
render_navigation("dense", current: :security)
end
layout.content do
render NitroKit::Flex.new(dir: :col, gap: 2, align: :stretch) do
6.times do |index|
render NitroKit::Card.new(id: "gallery-settings-layout-many-#{index + 1}") do |card|
card.body("Policy section #{index + 1}")
end
end
end
end
end
endNitro owns the single 48rem collapse while long labels and product copy remain application data.
The two regions stack automatically at the shared max-width: 48rem conditiontest/dummy/app/components/gallery/blocks/settings_layout_page.rbrender NitroKit::SettingsLayout.new(id: "gallery-settings-layout-long") do |layout|
layout.navigation(label: "Analytical Engines — International Research and Production settings") do
render NitroKit::ButtonGroup.new(label: "Long settings destinations") do |group|
group.button(
"Public organization identity and verified domains",
href: "#identity",
variant: :primary,
aria: { current: "page" }
)
group.button("Credential rotation and browser session policy", href: "#security")
group.button("Deployment notification delivery preferences", href: "#notifications")
end
end
layout.content do
render NitroKit::Card.new(id: "gallery-settings-layout-long-card") do |card|
card.title("Public organization identity and verified domains", level: 4)
card.body(
"These settings apply to every administrator, production environment, customer-visible status " \
"notification, security event, and invoice issued by this unusually long-named workspace."
)
end
end
endSettingsLayout owns only the two regions; Toolbar and PaginationBar retain their own placement contracts.
Showing audit records 1–25 of 240
test/dummy/app/components/gallery/blocks/settings_layout_page.rbrender NitroKit::SettingsLayout.new(id: "gallery-settings-layout-audit") do |layout|
layout.navigation(label: "Audit settings") do
render_navigation("audit", current: :activity)
end
layout.content do
render NitroKit::Flex.new(dir: :col, gap: 4, align: :stretch) do
render NitroKit::Toolbar.new(id: "gallery-settings-layout-audit-toolbar") do |toolbar|
toolbar.leading { h3 { "Audit retention" } }
toolbar.trailing do
render NitroKit::Button.new(
"Export records",
id: "gallery-settings-layout-audit-export",
variant: :primary
)
end
end
render NitroKit::PaginationBar.new(id: "gallery-settings-layout-audit-pagination-bar") do |bar|
bar.summary("Showing audit records 1–25 of 240")
bar.pagination(NitroKit::Pagination.new(label: "Audit record pages")) do |pagination|
pagination.prev
pagination.page(1, current: true)
pagination.page(2, href: "?page=2")
pagination.next(href: "?page=2")
end
end
end
end
end