SM content boundary
Uses --nk-content-sm; the surrounding application still owns available width.
Centered content maximums backed by the existing public width tokens.
app/components/nitro_kit/container.rbNitroKit::Container.new(size: :sm | :md | :lg | :xl); omit Container for full-width contentFour 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.
Uses --nk-content-sm; the surrounding application still owns available width.
Uses --nk-content-md; the surrounding application still owns available width.
Uses --nk-content-lg; the surrounding application still owns available width.
Uses --nk-content-xl; the surrounding application still owns available width.
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.description("Uses --nk-content-#{size}; the surrounding application still owns available width.")
end
end
end
endFull width is ordinary direct composition, not a fifth size or a special escape.
render NitroKit::Card.new(...) # no Container wrapperNo data-nk=container ancestor is emitted for this surface.
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.description("No data-nk=container ancestor is emitted for this surface.")
endA content boundary accepts empty, single, multiple, and long direct Phlex children.
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
endThis 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.description 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
endContainer owns only maximum width; stacks, rows, and Grid retain their independent responsibilities.
Owner · [email protected]
Admin · [email protected]
Member · [email protected]
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.description("#{member.role.to_s.humanize} · #{member.email}")
end
end
end
end
endThe first extraction wave stays smaller than the speculative vocabulary in the pivot plan.
No Spacer, Split, Frame, custom breakpoints, as:, or arbitrary CSS-value APIstest/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
endThe narrowest content boundary holds Gallery::Hostile's long name, unbroken word, long URL, long email, and four-sentence paragraph.
Wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
This description keeps going well past the point where a sensible product would have stopped, because real customers paste release notes, legal disclaimers, and entire support tickets into fields that were designed for a single line of text. This description keeps going well past the point where a sensible product would have stopped, because real customers paste release notes, legal disclaimers, and entire support tickets into fields that were designed for a single line of text. This description keeps going well past the point where a sensible product would have stopped, because real customers paste release notes, legal disclaimers, and entire support tickets into fields that were designed for a single line of text. This description keeps going well past the point where a sensible product would have stopped, because real customers paste release notes, legal disclaimers, and entire support tickets into fields that were designed for a single line of text.
test/dummy/app/components/gallery/components/container_page.rbrender NitroKit::Container.new(size: :sm, id: "gallery-container-hostile") do
render NitroKit::Card.new(id: "gallery-container-hostile-card") do |card|
card.title(Gallery::Hostile::LONG_NAME, level: 4)
card.body do
p { Gallery::Hostile::LONG_WORD }
p { a(href: Gallery::Hostile::LONG_URL) { Gallery::Hostile::LONG_URL } }
p { Gallery::Hostile::LONG_EMAIL }
p { Gallery::Hostile::LONG_PARAGRAPH }
end
card.footer do
render NitroKit::Button.new(
Gallery::Hostile::LONG_LABEL,
id: "gallery-container-hostile-action",
href: Gallery::Hostile::LONG_URL,
variant: :primary
)
end
end
endConstructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Container
size:, id: nildiv[data-nk=container]sm md lg xl; centered maximum width. Omit the component for full-width content.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.