Container
Centered content maximums backed by the existing public width tokens.
- Source
app/components/nitro_kit/container.rb- API
NitroKit::Container.new(size: :sm | :md | :lg | :xl); omit Container for full-width content
Content widths
Four existing content tokens provide centered maximum widths without arbitrary CSS values. The preview column is narrower than the lg and xl maximums, so those two clamp to the column here; widen the Responsive tab to see them diverge.
Every size
MD content boundary
LG content boundary
XL content boundary
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Flex.new(dir: :col, gap: 6, align: :stretch, id: "gallery-container-size-stack") do
NitroKit::Container::SIZES.each do |size|
render NitroKit::Container.new(size:, id: "gallery-container-size-#{size}") do
render NitroKit::Card.new(id: "gallery-container-size-#{size}-card") do |card|
card.title("#{size.to_s.upcase} content boundary", level: 4)
card.body("Uses --nk-content-#{size}; the surrounding application still owns available width.")
end
end
end
endFull-width boundary
Full width is ordinary direct composition, not a fifth size or a special escape.
Omit Container
- API
render NitroKit::Card.new(...) # no Container wrapper
Full available width
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Card.new(id: "gallery-container-full-width-card") do |card|
card.title("Full available width", level: 4)
card.body("No data-nk=container ancestor is emitted for this surface.")
endContent pressure
A content boundary accepts empty, single, multiple, and long direct Phlex children.
Empty, one, and many
test/dummy/app/components/gallery/components/container_page.rbsample("Empty", slug: "empty") do
render NitroKit::Container.new(size: :sm, id: "gallery-container-empty")
end
sample("One", slug: "one") do
render NitroKit::Container.new(size: :sm, id: "gallery-container-one") do
render NitroKit::Button.new(
"Intrinsic child",
id: "gallery-container-one-action",
variant: :primary
)
end
end
sample("Many", slug: "many") do
render NitroKit::Container.new(size: :md, id: "gallery-container-many") do
render NitroKit::Flex.new(dir: :col, gap: 2, align: :stretch) do
6.times do |index|
render NitroKit::Alert.new(id: "gallery-container-many-#{index + 1}") do |alert|
alert.title("Queued operation #{index + 1}")
alert.description("Waiting for deterministic processing.")
end
end
end
end
endLong readable boundary
Analytical Engines — International Research, Production, and Reliability Engineering
This account description stays inside the same readable maximum width even when customer-owned identity and operational context are substantially longer than the common case.
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Container.new(size: :md, id: "gallery-container-long") do
render NitroKit::Card.new(id: "gallery-container-long-card") do |card|
card.title(
"Analytical Engines — International Research, Production, and Reliability Engineering",
level: 4
)
card.body do
p do
"This account description stays inside the same readable maximum width even when customer-owned " \
"identity and operational context are substantially longer than the common case."
end
end
end
endNested compositions
Container owns only maximum width; stacks, rows, and Grid retain their independent responsibilities.
Wide workspace collection
Ada Lovelace
Grace Hopper
Katherine Johnson
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Container.new(size: :xl, id: "gallery-container-composition") do
render NitroKit::Flex.new(dir: :col, gap: 6, align: :stretch) do
render NitroKit::Flex.new(dir: :row, align: :center, gap: 2, justify: :between, wrap: :wrap) do
render NitroKit::Badge.new(
"12 active members",
id: "gallery-container-composition-status",
color: :success
)
render NitroKit::Button.new(
"Invite teammate",
id: "gallery-container-composition-action",
variant: :primary
)
end
render NitroKit::Grid.new(cols: "1 sm:2 lg:3", id: "gallery-container-composition-grid") do
Gallery::Data.members.each do |member|
render NitroKit::Card.new(id: "gallery-container-composition-#{member.id}") do |card|
card.title(member.name, level: 4)
card.body("#{member.role.to_s.humanize} · #{member.email}")
end
end
end
end
endEvidence boundary
The first extraction wave stays smaller than the speculative vocabulary in the pivot plan.
Deferred names
- API
No Spacer, Split, Frame, custom breakpoints, as:, or arbitrary CSS-value APIs
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Container.new(size: :lg, id: "gallery-container-deferred") do
render NitroKit::Alert.new(id: "gallery-container-deferred-alert") do |alert|
alert.title("Three layout names remain deliberately unimplemented")
alert.description(
"Spacer has no elastic-gap evidence and current rows use justify. Split appears in only one " \
"unsettled settings candidate. Frame has no flow evidence and would conflict with Turbo Frame language."
)
end
endComponent contract
Constructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Container
- Constructor
- required
size:,id: nil - Root
div[data-nk=container]- Contract
- Sizes
sm md lg xl; centered maximum width. Omit the component for full-width content.
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.