Production workspace
Stacks on small screens, then becomes a row without application CSS.
Responsive rows and columns with Tailwind-style breakpoint shorthand and closed layout values.
app/components/nitro_kit/flex.rbNitroKit::Flex.new(dir: "col md:row", gap: "2 md:4", align:, justify:, wrap:)Each property accepts a base value followed by the fixed sm md lg xl 2xl breakpoint prefixes; omitted breakpoints inherit the previous value.
dir: "col md:row", gap: "2 md:4 lg:6", align: "stretch md:center", justify: "start lg:between"Stacks on small screens, then becomes a row without application CSS.
test/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Container.new(size: :lg) do
render NitroKit::Flex.new(
dir: "col md:row",
gap: "2 md:4 lg:6",
align: "stretch md:center",
justify: "start lg:between",
wrap: "nowrap md:wrap",
id: "gallery-flex-responsive"
) do
render NitroKit::Card.new(id: "gallery-flex-responsive-summary") do |card|
card.title("Production workspace", level: 4)
card.description("Stacks on small screens, then becomes a row without application CSS.")
end
render NitroKit::Badge.new(
"12 active members",
id: "gallery-flex-responsive-status",
color: :success
)
render NitroKit::Button.new(
"Open workspace",
id: "gallery-flex-responsive-action",
variant: :primary
)
end
endbase + sm + md + lg + xl + 2xltest/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Flex.new(
dir: "col sm:row md:row-reverse lg:col-reverse xl:row 2xl:col",
gap: "1 sm:2 md:4 lg:8 xl:12 2xl:16",
align: "start sm:center md:end lg:stretch xl:baseline 2xl:center",
justify: "start sm:center md:end lg:between xl:around 2xl:evenly",
wrap: "nowrap sm:wrap md:wrap-reverse lg:nowrap xl:wrap 2xl:wrap-reverse",
id: "gallery-flex-breakpoints"
) do
6.times do |index|
render NitroKit::Badge.new(
"Region #{index + 1}",
id: "gallery-flex-breakpoint-#{index + 1}",
variant: :outline
)
end
endRows, columns, and their reverse forms share one primitive and the same responsive grammar.
test/dummy/app/components/gallery/components/flex_page.rb%w[row col row-reverse col-reverse].each do |direction|
sample(direction.humanize, slug: direction) do
render NitroKit::Flex.new(
dir: direction,
gap: 2,
align: :start,
id: "gallery-flex-dir-#{direction}"
) do
3.times do |index|
render NitroKit::Badge.new(
"Item #{index + 1}",
id: "gallery-flex-dir-#{direction}-#{index + 1}",
variant: :outline
)
end
end
end
endNumeric gaps follow Nitro's spacing unit. Alignment includes start, center, end, stretch, and baseline.
test/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Flex.new(
dir: :row,
gap: "1 sm:2 md:4 lg:8 xl:12 2xl:16",
align: :center,
wrap: :wrap,
id: "gallery-flex-gap-responsive"
) do
6.times do |index|
render NitroKit::Badge.new(
"Space #{index + 1}",
id: "gallery-flex-gap-responsive-#{index + 1}",
color: :info
)
end
endA second line makes cross-axis alignment visible.
A second line makes cross-axis alignment visible.
A second line makes cross-axis alignment visible.
A second line makes cross-axis alignment visible.
A second line makes cross-axis alignment visible.
test/dummy/app/components/gallery/components/flex_page.rb%w[start center end stretch baseline].each do |alignment|
sample(alignment.humanize, slug: alignment) do
render NitroKit::Flex.new(
dir: :row,
gap: 2,
align: alignment,
id: "gallery-flex-align-#{alignment}"
) do
render NitroKit::Card.new do |card|
card.body("Short")
end
render NitroKit::Card.new do |card|
card.body do
strong { "Taller surface" }
p { "A second line makes cross-axis alignment visible." }
end
end
end
end
endJustification and wrapping remain independent, responsive decisions.
test/dummy/app/components/gallery/components/flex_page.rb%w[start center end between around evenly].each do |justification|
sample(justification.humanize, slug: justification) do
render NitroKit::Flex.new(
dir: :row,
gap: 2,
align: :center,
justify: justification,
id: "gallery-flex-justify-#{justification}"
) do
render NitroKit::Button.new("Previous", size: :sm)
render NitroKit::Button.new("Continue", size: :sm, variant: :primary)
end
end
endtest/dummy/app/components/gallery/components/flex_page.rb%w[nowrap wrap wrap-reverse].each do |wrap|
sample(wrap.humanize, slug: wrap) do
render NitroKit::Container.new(size: :sm) do
render NitroKit::Flex.new(
dir: :row,
gap: 2,
align: :center,
wrap:,
id: "gallery-flex-wrap-#{wrap}"
) do
8.times do |index|
render NitroKit::Button.new("Environment #{index + 1}", size: :sm)
end
end
end
end
endResponsive properties combine for familiar headers and action regions without utility classes.
International Research, Production, and Reliability Engineering
test/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Container.new(size: :xl) do
render NitroKit::Flex.new(
dir: "col lg:row",
gap: "4 lg:6",
align: "stretch lg:center",
justify: "start lg:between",
id: "gallery-flex-composition"
) do
render NitroKit::Flex.new(dir: :col, gap: 1, align: :start) do
render NitroKit::Badge.new("Operational", color: :success)
h3 { "Analytical Engines" }
p { "International Research, Production, and Reliability Engineering" }
end
render NitroKit::Flex.new(
dir: :row,
gap: 2,
align: :center,
justify: :end,
wrap: :wrap,
id: "gallery-flex-composition-actions"
) do
render NitroKit::Button.new("View activity")
render NitroKit::Button.new("Create deployment", variant: :primary)
end
end
endThirty Gallery::Hostile badge labels in a wrapping row, then a no-wrap responsive row whose children carry the unbroken word, huge number, long label, and long paragraph.
test/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Flex.new(
dir: :row,
gap: 2,
align: :center,
wrap: :wrap,
id: "gallery-flex-hostile-wrap"
) do
Gallery::Hostile::BADGE_LABELS.each_with_index do |label, index|
render NitroKit::Badge.new(
label,
id: "gallery-flex-hostile-wrap-#{index}",
variant: :outline
)
end
endtest/dummy/app/components/gallery/components/flex_page.rbrender NitroKit::Flex.new(
dir: "col md:row",
gap: "2 md:4",
align: "stretch md:center",
justify: "start md:between",
wrap: :nowrap,
id: "gallery-flex-hostile-nowrap"
) do
render NitroKit::Card.new(id: "gallery-flex-hostile-nowrap-card") do |card|
card.title(Gallery::Hostile::LONG_WORD, level: 4)
card.body(Gallery::Hostile::LONG_PARAGRAPH)
end
render NitroKit::Badge.new(
Gallery::Hostile::HUGE_FORMATTED,
id: "gallery-flex-hostile-nowrap-badge",
color: :success
)
render NitroKit::Button.new(
Gallery::Hostile::LONG_LABEL,
id: "gallery-flex-hostile-nowrap-action",
variant: :primary
)
endConstructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Flex
dir:; gap: 4, align: :start, justify: :start, wrap: :nowrap, id: nildiv[data-nk=flex]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.