Starter
One workspace, Three members, and Community support
Responsive one-to-twelve-column collections with Tailwind-style breakpoint shorthand.
app/components/nitro_kit/grid.rbNitroKit::Grid.new(cols: "1 sm:2 lg:3", gap: "2 md:4")Column and gap values use the same base, sm, md, lg, xl, and 2xl shorthand as Flex.
cols: "1 sm:2 lg:3", gap: "3 md:4 lg:6"One workspace, Three members, and Community support
Unlimited workspaces, Twenty members, and Email support
Unlimited members, Audit log, and Priority support
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.description(plan.features.to_sentence)
card.footer do
card.actions do
render NitroKit::Button.new(
plan.current ? "Manage" : "Choose",
variant: plan.current ? :default : :primary,
size: :sm
)
end
end
end
end
end
endtest/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
endA scalar keeps one column count at every viewport; the closed range is one through twelve.
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
endColumns and spacing can change at different breakpoints without exposing arbitrary CSS values.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
A roomy card collection gains columns gradually.
128430 requests
256860 requests
385290 requests
513720 requests
642150 requests
770580 requests
899010 requests
1027440 requests
1155870 requests
1284300 requests
1412730 requests
1541160 requests
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}", size: :sm) do |card|
card.title("Integration #{index + 1}", level: 4)
card.description("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}", size: :sm) do |card|
card.title("Region #{index + 1}", level: 4)
card.description("#{(index + 1) * 128_430} requests")
end
end
end
endEmpty, partial, dense, and uneven collections retain the declared responsive contract.
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
Deterministic collection item
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(size: :sm) do |card|
card.title("Record #{index + 1}", level: 4)
card.description("Deterministic collection item")
end
end
end
end[email protected]
International Research, Production, and Reliability Engineering
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.header do
card.title(member.name, level: 4)
card.description do
plain member.email
if member == Gallery::Data.members.first
br
plain "International Research, Production, and Reliability Engineering"
end
end
card.actions do
render NitroKit::Badge.new(
member.status.to_s.humanize,
color: member.status == :active ? :success : :info,
size: :sm
)
end
end
card.divider
card.footer do
card.actions do
render NitroKit::Button.new("View", size: :sm)
render NitroKit::Button.new("Change role", size: :sm)
end
end
end
end
endForty Gallery::Hostile member cards in a responsive grid, then thirty hostile badge labels forced into twelve fixed tracks.
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
maximiliana.wolfeschlegelsteinhausenbergerdorff+billing.notifications.eu-west-2026@finance.department.enterprise-holdings-international.example
ünïcödé.tëst+ß@exämple-bücher.test
用户@例子.广告
wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege@wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflege.example
test/dummy/app/components/gallery/components/grid_page.rbrender NitroKit::Grid.new(
cols: "1 sm:2 lg:4",
gap: "2 lg:4",
id: "gallery-grid-hostile-members"
) do
Gallery::Hostile.members(40).each do |member|
render NitroKit::Card.new(id: "gallery-grid-hostile-member-#{member.id}") do |card|
card.title(member.name, level: 4)
card.body do
render NitroKit::Badge.new(
member.role.to_s.humanize,
id: "gallery-grid-hostile-member-#{member.id}-role",
size: :sm
)
p { member.email }
end
end
end
endtest/dummy/app/components/gallery/components/grid_page.rbrender NitroKit::Grid.new(cols: 12, gap: 1, id: "gallery-grid-hostile-tracks") do
Gallery::Hostile::BADGE_LABELS.each_with_index do |label, index|
render NitroKit::Badge.new(
label,
id: "gallery-grid-hostile-track-#{index}",
color: :info
)
end
endConstructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Grid
cols:; gap: 4, id: nildiv[data-nk=grid]minmax(0, 1fr) tracks; direct content; empty content is valid.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.