Welcome to Oshon · v1.0  ·  Now in public beta for enterprise teams Read the launch notes
CommunicationUpdatedFree

Empty State

Brand-aligned zero-state surface — 12 type presets × 5 sizes × 3 layouts.

Preview

Live preview
@oshon-ai/components
Default — type preset supplies icon + copy

Nothing here yet

Your data will show up once available.

All 12 type presets — 3 per row

Nothing here yet

Your data will show up once available.

No results found

Try a different search or adjust your filters.

Inbox empty

You have no messages yet.

No favorites

You have nothing on your list yet.

Cart empty

Start adding items to enjoy shopping.

No notifications

You have no notifications yet. Please come back later.

No pictures

Capture new moments or upload your favorite images.

No connection

It looks like you're currently offline.

404

The page you're looking for can't be found.

Enable location

For personalized recommendations, please enable location services.

Something went wrong

Please try again in a moment.

Custom

Bring your own icon + copy.

With an action button

No results found

Try a different search or adjust your filters.

With action + helper link

404

The page you're looking for can't be found.

Layouts — centered / inline / stacked

Inbox empty

You have no messages yet.

Inbox empty

You have no messages yet.

Inbox empty

You have no messages yet.

Sizes

Size xs

Same content across the size axis.

Size s

Same content across the size axis.

Size m

Same content across the size axis.

Size l

Same content across the size axis.

Size mobile

Same content across the size axis.

Installation

Install the runtime packages:

pnpm
pnpm add @oshon-ai/components @oshon-ai/tokens @oshon-ai/primitives

Or scaffold the component source directly into your codebase (shadcn-style):

pnpm
pnpm dlx @oshon-ai/cli add emptystate

Wire the tokens into your Tailwind v4 stylesheet:

css
/* app/globals.css */
@import 'tailwindcss';
@import '@oshon-ai/tokens/css';
@import '@oshon-ai/tokens/tailwind';

New here? Walk through the full setup — prereqs, theming, your first render.

Usage

Import the component and render it. Every component supports the standard tier, size, and disabled props where applicable.

tsx
'use client';
import { EmptyState } from '@oshon-ai/components';

export default function Example() {
  return <EmptyState />;
}

Styling

Three layers of customization, in order of escape-hatch strength: className overrides → data-attribute targeting → CSS custom properties.

Passing Tailwind classes

Every Oshon component accepts a className prop merged AFTER the component's default classes. Use it to override spacing, color, or size without forking the component.

tsx
<EmptyState
  className="ring-2 ring-offset-2 ring-blue-500"
/>

Data attributes

Oshon components expose their internal state as data-oshon-* attributes so you can target them from CSS without coupling to internal class names. The most common attributes are listed below — see the component's source for the full set.

AttributeValuesDescription
data-oshon-sizexs · s · m · l · mobileVisual size axis. Mirrors the `size` prop.
data-oshon-tierprimary · secondary · tertiaryVisual emphasis tier (Button family). Mirrors the `tier` prop.
data-oshon-stateenabled · active · error · disabledComponent surface state. Set automatically based on props.
data-disabledtrue · (omitted)Set when `disabled` is true. Pair with `:disabled` CSS for native input components.
data-stateopen · closed · checked · unchecked · …Radix-derived state for overlay components (Dialog, Tabs, Toggle, etc.).
css
/* Target the secondary tier specifically */
[data-oshon-tier="secondary"] {
  --oshon-color-primary-700: var(--my-brand-color);
}

Interactive states

Every interactive component supports the standard CSS pseudo- classes plus Tailwind's state variants. Focus rings always use :focus-visible so keyboard users see them but mouse users don't.

  • :hover / hover:* — pointer hover
  • :focus-visible / focus-visible:* — keyboard focus
  • :active / active:* — pressed
  • :disabled / disabled:* — set via the disabled prop