Sheet
A native modal side panel for narrow navigation and contextual details.
- Source
app/components/nitro_kit/sheet.rb- API
NitroKit::Sheet.new(id:, side:, size:) { |sheet| sheet.trigger; sheet.panel }
Side panels
A native modal dialog enters from either inline edge without changing surrounding flex or grid layout.
Navigation and details
Viewport
Ruby
test/dummy/app/components/gallery/components/sheet_page.rbprompts = [
[ "Set up the project", "#prompt-1" ],
[ "Review the implementation", "#prompt-2" ],
[ "Prepare the release", "#prompt-3" ]
]
render NitroKit::Sheet.new(id: "gallery-sheet-prompts", side: :left, size: :sm) do |sheet|
sheet.trigger("Prompts", icon: :list)
sheet.panel(
title: "Transcript prompts",
description: "Jump to a prompt in this transcript."
) do
render NitroKit::AppNavigation.new(label: "Transcript prompts") do |navigation|
navigation.body do |items|
prompts.each_with_index do |(text, href), index|
items.item(text, href:, current: index.zero?)
end
end
end
end
end
render NitroKit::Sheet.new(id: "gallery-sheet-details", side: :right, size: :md) do |sheet|
sheet.trigger("Record details", icon_end: :panel_right)
sheet.panel(title: "Deployment 1842", description: "Production release details") do
render NitroKit::DetailsTable.new(
Deployment.new(environment: "Production", status: "Running", owner: "Ada Lovelace"),
label: "Deployment details"
) do |details|
details.fields(:environment, :status, :owner)
end
end
endSizes, long content, and unavailable
A large sheet scrolls long content past its sticky close control with a custom close label; a disabled trigger keeps the panel unreachable.
Viewport
Ruby
test/dummy/app/components/gallery/components/sheet_page.rbrender NitroKit::Sheet.new(
id: "gallery-sheet-long",
side: :right,
size: :lg,
close_label: "Close changelog"
) do |sheet|
sheet.trigger("Full changelog")
sheet.panel(
title: "Release changelog",
description: "Every change since the previous production deploy."
) do
12.times do |index|
p do
"Change #{index + 1}. Deploy #{1830 + index} refreshed the ingestion " \
"pipeline, rotated its credentials, and re-ran the archived backfill " \
"verification for every affected workspace."
end
end
end
end
render NitroKit::Sheet.new(id: "gallery-sheet-disabled", side: :right, size: :sm) do |sheet|
sheet.trigger("Deployment details", disabled: true)
sheet.panel(title: "Deployment details")
endComponent contract
Constructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::Sheet
- Constructor-specific options
- required
id: side: :right,size: :md,close_label:
- required
- Root and closed vocabulary
- layout-transparent
div[data-nk=sheet][data-side][data-size]owning one native dialog; sidesleft right; sizessm md lg - Compound contract
- Requires exactly one Button-backed
triggerand onepanel(title:, description: nil); both carry the sharedhtml:,aria:,data:, anddesperately_need_a_class:boundary, panel attributes landing on the dialog element as in Dialog. The native modal panel fills the block axis and enters from the selected inline edge. Nitro owns close, title, description, body order, backdrop dismissal, and native focus containment. Use Sheet for contextual narrow navigation or details; use AppShell for whole-application navigation and Dialog for centered decisions.
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.