Recent deployments
No deployments this week
Promote a release to see it listed here.
An explicit empty result with controlled heading hierarchy, icon, and up to two actions.
EmptyState is content, not application policy: callers choose copy, destinations, and whether zero, one, or two actions are appropriate.Supply the required title through title: or title { ... }; description supports the same two forms. variant: accepts :default or :borderless and level: accepts 2..6. icon accepts one Icon and action accepts at most two distinct Buttons.variant: is a closed vocabulary of default and borderless; any other value raises ArgumentError. The dashed default frames a standalone region and deliberately resembles a drop target, so prefer borderless whenever a Card, DataSection, table, or dialog already draws the frame — and never place the dashed default next to a real Dropzone.
The dashed frame marks an otherwise unframed region of the page.
Inside a frame of its own, the empty state drops its border and fill.
test/dummy/app/components/gallery/components/empty_state_page.rbsample("Default", slug: "default") do
render NitroKit::EmptyState.new(
title: "No saved views",
description: "The dashed frame marks an otherwise unframed region of the page.",
id: "gallery-empty-state-variant-default"
) do |empty|
empty.icon NitroKit::Icon.new(:layout_grid)
end
end
sample("Borderless", slug: "borderless") do
render NitroKit::EmptyState.new(
title: "No saved views",
description: "Inside a frame of its own, the empty state drops its border and fill.",
variant: :borderless,
id: "gallery-empty-state-variant-borderless"
) do |empty|
empty.icon NitroKit::Icon.new(:layout_grid)
end
endThe card owns the surface and border, so a dashed empty state inside it would read as a second, droppable surface.
Promote a release to see it listed here.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::Card.new(id: "gallery-empty-state-card") do |card|
card.title("Recent deployments", level: 3)
card.body do
render NitroKit::EmptyState.new(
title: "No deployments this week",
description: "Promote a release to see it listed here.",
variant: :borderless,
level: 4,
id: "gallery-empty-state-in-card"
) do |empty|
empty.icon NitroKit::Icon.new(:rocket)
empty.action NitroKit::Button.new("Promote a release", href: "#promote", variant: :primary)
end
end
endHeading levels, optional icon and description, and zero through two typed actions.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::EmptyState.new(title: "No records", id: "gallery-empty-state-title-only")Requests will appear after a credential makes its first call.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::EmptyState.new(
title: "No API activity yet",
description: "Requests will appear after a credential makes its first call.",
id: "gallery-empty-state-information"
) do |empty|
empty.icon NitroKit::Icon.new(:activity)
endInvite the first collaborator when the workspace is ready.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::EmptyState.new(
title: "No teammates yet",
description: "Invite the first collaborator when the workspace is ready.",
id: "gallery-empty-state-one-action"
) do |empty|
empty.icon NitroKit::Icon.new(:users)
empty.action NitroKit::Button.new("Invite teammate", href: "#invite", variant: :primary)
endChange the date range or clear every filter to return to invoice history.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::EmptyState.new(
title: "No matching invoices",
description: "Change the date range or clear every filter to return to invoice history.",
id: "gallery-empty-state-two-actions"
) do |empty|
empty.icon NitroKit::Icon.new(:search_x)
empty.action NitroKit::Button.new("Clear filters", href: "#clear", variant: :primary)
empty.action NitroKit::Button.new("Return to billing", href: "#billing")
endThe current search includes archived projects, suspended members, expired credentials, and a date range that predates this workspace. Remove one or more filters before trying again.
test/dummy/app/components/gallery/components/empty_state_page.rbrender NitroKit::Container.new(size: :md, id: "gallery-empty-state-long-container") do
render NitroKit::EmptyState.new(
level: 4,
id: "gallery-empty-state-long"
) do |empty|
empty.title do
plain "No records for "
strong { "International Research, Production, and Reliability Engineering" }
end
empty.description do
plain "The current search includes archived projects, suspended members, expired credentials, and a date range that predates this workspace. "
plain "Remove one or more filters before trying again."
end
empty.icon NitroKit::Icon.new(:database)
empty.action NitroKit::Button.new("Reset all filters", href: "#reset", variant: :primary)
empty.action NitroKit::Button.new("Review query guide", href: "#guide")
end
endConstructor options, rendered root, closed vocabularies, and compound boundary for this component, exactly as shipped.
docs/component_contracts.md · NitroKit::EmptyState
title: nil, description: nil, variant: :default, level: 2, id: nilsection[data-nk=empty-state][data-variant]; variants default borderlesstitle; title and description each accept constructor text or one matching text/rich-content compound declaration. Heading levels 2..6; at most one Icon and two distinct Button actions. default draws the dashed frame for a standalone region; borderless drops frame and fill for a region a Card, DataSection, or table already encloses, where the dashed frame would read as a Dropzone. Declaring a compound method outside the render block raises.Application conventions this component belongs to. Each summary is the leading section of its pattern document.
docs/patterns/crud_resource.md
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.