nili/ui
v0.2.0 — registry and CLI

One library,whatever language you add

Nili is a React component library that treats direction, script, numerals and type metrics as inputs — not a translation layer bolted on at the end.

$npm i @nili/ui @remixicon/react
41components
220sub-components
196variant axes
869typed props
374passing tests

Any locale, one component tree

Direction comes from CSS, numerals from Intl, and neither is a prop. These four are only what is shown — the next language is a translation file and a locale, not a fork.

EnglishActive
فارسیفعال
العربيةنشط
TürkçeEtkin
AZ
Aysan ZeinalvandMerchant account
Active
Next payout settles on 17 September.
Available balance
1,234,567IRT
68% of the monthly cap18,000,000

Three problems every multilingual UI hits

These are usually solved app by app, badly. Nili solves them once, at the library level.

01

Direction is CSS, not JavaScript

Every component uses logical properties — ms/me, ps/pe, start/end. They work inside a nested RTL subtree, they work under SSR because nothing reads document.dir during render, and there is no direction prop to thread through the tree.

dir="ltr"dir="rtl"
02

Digits are formatting, never a font trick

A FaNum font cut maps local digit glyphs onto ASCII codepoints: numbers look local while the DOM still holds 123, so find-in-page, copy-paste and screen readers all disagree with the screen — and a value that must stay Latin, like an IBAN, cannot.

formatNumber · en-US1,234,567.89
formatNumber · fa-IR۱٬۲۳۴٬۵۶۷٫۸۹
formatNumber · ar-EG١٬٢٣٤٬٥٦٧٫٨٩
formatNumber · tr-TR1.234.567,89
parseLocalizedNumber۱٬۲۳۴٬۵۶۷ → 1234567
03

One token name, both themes

Components never write dark:. A component names one semantic token and the value swaps underneath it, so a new theme — high contrast, a tenant brand — is a stylesheet, not a refactor.

primitive--nili-blue-500: #335CFF
semantic--nili-primary-base
@theme--color-primary-base
componentbg-primary-base
The whole page swaps

Private for now

Nili is published to a private npm scope under an UNLICENSED package, and the source is not public yet. Access is granted per person or team, and once your token is in place the install is a normal npm install.

01

Request access

Tell us the project and the npm or GitHub account to add to the @nili org.

02

Authenticate the registry

Add a read-only token to your .npmrc — locally and in CI.

03

Install and wrap

Install the package, import the stylesheet, wrap the tree in NiliProvider.

# .npmrc
@nili:registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NILI_TOKEN}

# then
npm i @nili/ui @remixicon/react
import { NiliProvider, Button } from '@nili/ui';
import '@nili/ui/styles.css';

<NiliProvider locale="fa" defaultTheme="system">
  <Button color="primary">Save changes</Button>
</NiliProvider>

Who built it

Two people: one design file and one library, kept in sync on purpose.

AZ

Aysan Zeinalvand

Design system engineering — architecture, components, tokens, tests

Wrote the library: the token pipeline, the RTL and numeral layers, the component API conventions, the registry and CLI, and the 374 tests behind them.

BR

Behzad Rezazadeh

Product design — the Figma source of truth

Designed the system in Figma: the colour ramps, the type scale, component anatomy and every variant the library implements.

Want it on your project?

Tell us what you are building and we will set up access, or walk through the system with your team.