Grid
Responsive one-to-twelve-column collections with Tailwind-style breakpoint shorthand.
- Source
app/components/nitro_kit/grid.rb- API
NitroKit::Grid.new(cols: "1 sm:2 lg:3", gap: "2 md:4")
Mobile-first columns
Column and gap values use the same base, sm, md, lg, xl, and 2xl shorthand as Flex.
One to three cards
- API
cols: "1 sm:2 lg:3", gap: "3 md:4 lg:6"
Team
Business
test/dummy/app/components/gallery/components/grid_page.rbrender NitroKit::Container.new(size: :xl) do
render NitroKit::Grid.new(
cols: "1 sm:2 lg:3",
gap: "3 md:4 lg:6",
id: "gallery-grid-cards"
) do
Gallery::Data.plans.each do |plan|
render NitroKit::Card.new(id: "gallery-grid-card-#{plan.id}") do |card|
card.title(plan.name, level: 4)
card.body(plan.features.to_sentence)
card.footer do
render NitroKit::Button.new(
plan.current ? "Manage" : "Choose",
variant: plan.current ? :default : :primary
)
end
end
end
end
endEvery breakpoint
test/dummy/app/components/gallery/components/grid_page.rbrender NitroKit::Grid.new(
cols: "1 sm:2 md:3 lg:4 xl:6 2xl:12",
gap: "1 sm:2 md:3 lg:4 xl:6 2xl:8",
id: "gallery-grid-breakpoints"
) do
12.times do |index|
render NitroKit::Badge.new(
"Track #{index + 1}",
id: "gallery-grid-breakpoint-#{index + 1}",
variant: :outline
)
end
endScalar columns
A scalar keeps one column count at every viewport; the closed range is one through twelve.
Representative counts
test/dummy/app/components/gallery/components/grid_page.rb[ 1, 2, 3, 4, 6, 12 ].each do |cols|
sample("#{cols} #{'column'.pluralize(cols)}", slug: "cols-#{cols}") do
render NitroKit::Grid.new(cols:, gap: 1, id: "gallery-grid-cols-#{cols}") do
cols.times do |index|
render NitroKit::Badge.new(
"#{index + 1}",
id: "gallery-grid-cols-#{cols}-#{index + 1}",
color: :info
)
end
end
end
endIndependent responsive decisions
Columns and spacing can change at different breakpoints without exposing arbitrary CSS values.
Two useful collection shapes
Integration 1
Integration 2
Integration 3
Integration 4
Integration 5
Integration 6
Integration 7
Integration 8
Region 1
Region 2
Region 3
Region 4
Region 5
Region 6
Region 7
Region 8
Region 9
Region 10
Region 11
Region 12
test/dummy/app/components/gallery/components/grid_page.rbsample("Catalog", slug: "catalog") do
render NitroKit::Grid.new(
cols: "1 md:2 xl:4",
gap: "2 lg:6",
id: "gallery-grid-catalog"
) do
8.times do |index|
render NitroKit::Card.new(id: "gallery-grid-catalog-#{index + 1}") do |card|
card.title("Integration #{index + 1}", level: 4)
card.body("A roomy card collection gains columns gradually.")
end
end
end
end
sample("Metrics", slug: "metrics") do
render NitroKit::Grid.new(
cols: "2 lg:4 2xl:6",
gap: "2 md:3",
id: "gallery-grid-metrics"
) do
12.times do |index|
render NitroKit::Card.new(id: "gallery-grid-metric-#{index + 1}") do |card|
card.title("Region #{index + 1}", level: 4)
card.body("#{(index + 1) * 128_430} requests")
end
end
end
endContent pressure
Empty, partial, dense, and uneven collections retain the declared responsive contract.
Empty, one, and many
Record 1
Record 2
Record 3
Record 4
Record 5
Record 6
Record 7
Record 8
Record 9
test/dummy/app/components/gallery/components/grid_page.rbsample("Empty", slug: "empty") do
render NitroKit::Grid.new(cols: "1 md:3", gap: 4, id: "gallery-grid-empty")
end
sample("One", slug: "one") do
render NitroKit::Grid.new(cols: "1 md:3", gap: 4, id: "gallery-grid-one") do
render NitroKit::Card.new do |card|
card.body("One item occupies one track; Grid does not invent a span API.")
end
end
end
sample("Many", slug: "many") do
render NitroKit::Grid.new(cols: "1 sm:2 lg:3", gap: 2, id: "gallery-grid-many") do
9.times do |index|
render NitroKit::Card.new do |card|
card.title("Record #{index + 1}", level: 4)
card.body("Deterministic collection item")
end
end
end
endUneven team records
Ada Lovelace
Grace Hopper
Katherine Johnson
test/dummy/app/components/gallery/components/grid_page.rbrender NitroKit::Grid.new(
cols: "1 sm:2 lg:3",
gap: "3 lg:6",
id: "gallery-grid-team"
) do
Gallery::Data.members.each do |member|
render NitroKit::Card.new(id: "gallery-grid-team-#{member.id}") do |card|
card.title(member.name, level: 4)
card.body do
render NitroKit::Flex.new(dir: :col, gap: 2, align: :start) do
render NitroKit::Badge.new(
member.status.to_s.humanize,
color: member.status == :active ? :success : :info
)
p { member.email }
p { "International Research, Production, and Reliability Engineering" } if member == Gallery::Data.members.first
end
end
card.footer do
render NitroKit::Flex.new(dir: :row, gap: 1, align: :center, wrap: :wrap) do
render NitroKit::Button.new("View", size: :sm)
render NitroKit::Button.new("Change role", size: :sm)
end
end
end
end
endComponent contract
Constructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Grid
- Constructor
- required
cols:;gap: 4,id: nil - Root
div[data-nk=grid]- Contract
- Columns and gap accept scalar or responsive values. Equal
minmax(0, 1fr)tracks; direct content; empty content is valid.
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.