Hashti

A design system built as a vestibule between the street and the courtyard.

Hashti is named for the octagonal room where a visitor leaves the noise behind. The components carry that pause: clear labels, quiet surfaces, and state you can trust.

Change the room, not the code

Used in the address bar of every preview.

44pxminimum control height

4.5:1contrast, both themes

1stylesheet, no runtime

326stories swept every release

Four rooms, one crossing

Persian houses never moved a guest in a straight line. The same sequence organises this library: an announcement, a settling room, a corridor, and the courtyard beyond.

  1. Darvazeh

    دروازه

    A pointed arch marks the boundary. A command states what it will do before the system does it.

  2. Hashti

    هشتی

    The octagonal room where light settles and attention re-forms. Overlays, focus containment, and quiet state live here.

  3. Dalan

    دالان

    A bent corridor that refuses a straight line of sight. Depth in the system is a passage, never a drop shadow.

  4. Hayati

    حیاطی

    The courtyard, where the work actually happens. Calm surfaces, honest contrast, and room to stay.

Read the architectural notes

What the system promises

Every promise here is measured in the rendered browser, not asserted in a README. The same checks gate each release.

Behaviour
React Aria Components: roving tab index, typeahead, screen-reader semantics.
Composition
Trigger, value, and popover stay separate parts instead of one prop matrix.
Contrast
Essential controls hold 4.5:1, body text 7:1, in every shipped theme.
Tokens
Layered CSS custom properties. No style engine, no hashing, no hydration cost.
Focus
A two-pixel ring outside the control, keyboard only, never animated.
Longevity
Apache 2.0, one stylesheet, no runtime dependency on the theme package.

Start at the threshold

One stylesheet import, one theme boundary, then compose. Nothing is fetched at runtime and no provider configures a stylesheet.

bun add @hashti/react @hashti/tokens react-aria-components

import "@hashti/tokens/tokens.css";
import "@hashti/react/styles.css";

import { Theme, Button } from "@hashti/react";

export function Threshold() {
  return (
    <Theme theme="frame-light">
      <Button variant="primary" onPress={openPortal}>
        Enter portal
      </Button>
    </Theme>
  );
}
Full installation guide