An address can fail to name anything. A position id with no position behind it, a
removal that never happened, a chain that was never migrated: the route matched
the shape of the path, and the subject it was asked for does not exist.
Nowhere is what that screen says.
The failure it makes visible
Nowhere came out of the Lux exchange, where a screen is reached by a link that
carries what to read — a position, a removal, a migration — and answers a family
of paths rather than a single one. A path in the family that named nothing
matched no page at all and left an empty <main>: a heading, a footer, and
nothing between them. That reads as a venue with nothing in it rather than as a
link that does not resolve.
A blank page is also the failure a sweep does not catch. An empty document reports the same width as a full one and raises no layout complaint, so every measurement passes on it. Saying so on screen is what turns it back into something a person and a test both notice.
It sits before the reading, not inside it
Table and Tally take a reading rather than a value, because a component that
has flattened "there is nothing" and "we could not ask" into an empty list cannot
tell them apart afterwards.
type Rows<R> =
| { at: 'reading' }
| { at: 'read'; rows: R[] }
| { at: 'failed'; why: string }Nowhere is neither branch. No read was attempted, because there was nothing to
read about, and its note says exactly that: Nothing was read, so nothing here is
a statement about a market.
That separates it from what a table says over the same blank space. Table
writes those through Answer, which is exported for the case where a screen
fails before there is a table to fail in:
| Component | The statement it makes |
|---|---|
Nowhere | The address named no subject, so nothing was asked. |
Answer | We read, and the answer was nothing. |
Answer with alert | We could not read. The reason is on screen, in the colour of a refusal. |
Nowhere is the page. Answer is a card in the region that would have held the
rows.
Installation
npm install @luxfi/ui @hanzo/gui @hanzo/ui @hanzo/design @tanstack/react-queryimport '@luxfi/ui/tokens.css'
import '@hanzo/design/styles.css'
import { AppProvider } from '@luxfi/ui/provider'
import { Nowhere } from '@luxfi/ui/read'AppProvider goes once at the root of the app and mounts the gui engine and a
query client. The two sheets are where the names resolve: colour from
@luxfi/ui/tokens.css, spacing, elevation and measure from @hanzo/design.
Usage
import { Nowhere } from '@luxfi/ui/read'<Nowhere what="market" />The route decides that the address named nothing. Nowhere states it.
export default function Market({ params }: { params: { id: string } }) {
const market = markets.find((m) => m.id === params.id)
if (!market) return <Nowhere what="market" />
return <MarketDetail market={market} />
}Anything offered to the reader — a correction, a way back — arrives as
children, and lands in the note beside the sentence.
<Nowhere what="position">
<a href="/positions">Open the positions list.</a>
</Nowhere>Props
| Prop | Type | Required |
|---|---|---|
what | string | yes |
children | ReactNode | no |
what is a singular noun in the reader's own words, and it is written into both
sentences — This link names no {what} as the heading, …a statement about a {what} in the note. So it has to read after no and after a: market,
position, migration, not markets and not Market ID.
The heading renders as <h1>, because Nowhere replaces the page rather than
sitting in it. Both lines take their colour from paint — --color-text-primary
for the heading, --color-text-secondary for the note — and the note is held to
a 560-pixel measure, past which a line of this type stops being readable.
What it does not do
Nowhere is markup. It does not fetch, retry, redirect, or decide that the
address named nothing; the route does that and renders this in place of the page.
It sets no HTTP status; that belongs to whatever resolved the address, and a
surface that owes a 404 has to say so there. It carries no illustration and no
action of its own. The article in the note is fixed at a, which reads wrong in
front of a vowel, so order wants rewording rather than passing straight
through. And it says nothing about a read that
happened: a query that came back empty, and one that came back refused, are
Table's empty and Rows.failed, and drawing either of them as this link
names nothing would be the same substitution in the other direction.