dir="ltr"
Invoice INV-2041 فاتورة
Paid by Northwind Traders, ودفعت الفاتورة كاملة في 14 October.
dir="rtl"
فاتورة INV-2041 Invoice
دفعت الفاتورة كاملة من Northwind Traders في 14 تشرين الأول.
import { Card } from "@hel/ui/card"
import { Flex } from "@hel/ui/flex"
import { Heading } from "@hel/ui/heading"How it works#
Hel UI is built for apps that mix English and Arabic, on the same screen and sometimes in the same sentence. So a font setting has two parts: one font for Latin text, and one for Arabic text. The two are listed together in one stack, and the browser picks the font per character. An English name inside an Arabic sentence gets the Latin font, and an Arabic word inside an English page gets the Arabic one.
Only the order changes with the direction. In a left-to-right layout the Latin font is tried first. In a right-to-left layout, in lang="ar" content, and inside any element with dir="rtl", the Arabic font is tried first. A left-to-right island inside right-to-left content goes back to Latin first. The two cards in the preview above are the same markup with different dir values.
The defaults are Inter for Latin and IBM Plex Sans Arabic for Arabic, with the system font as the last resort.
Choose your fonts#
Set them in the config. Each language has a body font and an optional heading font, which falls back to the body font.
import { defineConfig } from "@hel/ui/config"
export const helConfig = defineConfig({
fonts: {
latin: { body: "Geist", heading: "Geist" },
arabic: { body: "Cairo" },
fallback: ["system-ui", "sans-serif"],
},
})The config only names a font. It does not load it, so the name has to match the font-family of the font you load. fallback replaces the whole list, because arrays are not merged. Names with spaces or digits are quoted for you.
Load the font files#
@hel/ui/fonts.css loads the default fonts, Inter in six weights and IBM Plex Sans Arabic in four, from Fontsource. Each file is split by unicode range, so the browser downloads only the parts a page uses.
@import "tailwindcss";
@import "@hel/ui/styles.css";
@import "@hel/ui/fonts.css";If you choose other fonts, leave fonts.css out and load your own, so no font that you do not use is downloaded. Fontsource is the quickest way:
pnpm add @fontsource/geist @fontsource/cairo@import "@fontsource/geist/400.css";
@import "@fontsource/geist/500.css";
@import "@fontsource/geist/600.css";
@import "@fontsource/cairo/arabic-400.css";
@import "@fontsource/cairo/arabic-600.css";Load the weights that the components use. Text is regular (400) and medium (500), and headings and some labels are semibold (600).
Regular 400
Order shipped تم الشحن
Medium 500
Order shipped تم الشحن
Semibold 600
Order shipped تم الشحن
Bold 700
Order shipped تم الشحن
import { Flex } from "@hel/ui/flex"
import { Stack } from "@hel/ui/stack"
import { Text } from "@hel/ui/text"Set the variables yourself#
The config writes five CSS variables on :root, and you can write them in CSS instead. This is the way to use a font loaded by a framework such as next/font, which gives you a variable that holds the family name.
:root {
--hel-font-latin-body: var(--font-geist);
--hel-font-latin-heading: var(--hel-font-latin-body);
--hel-font-arabic-body: "Cairo";
--hel-font-arabic-heading: var(--hel-font-arabic-body);
--hel-font-fallback: system-ui, sans-serif;
}The stacks that components read are built from these. --brand-font-family-body and --brand-font-family-headings hold the final lists, in the right order for the direction.
A custom property is inherited after it has been resolved. So if you change --hel-font-* on an element in the middle of the page, the text inside does not follow. Set the variables on :root, or set --brand-font-family-body on the element.
In your own code#
Components already use the right stack. For your own elements, use the font utilities of Tailwind, or inherit.
<p className="font-body">Follows the config and the direction</p>Config reference#
| Key | Type | Default |
|---|---|---|
fonts.latin.body | string | "Inter" |
fonts.latin.heading | string | the body font |
fonts.arabic.body | string | "IBM Plex Sans Arabic" |
fonts.arabic.heading | string | the body font |
fonts.fallback | string[] | system-ui, -apple-system, Segoe UI, sans-serif |
| Variable | Meaning |
|---|---|
--hel-font-latin-body, --hel-font-latin-heading | The Latin fonts. |
--hel-font-arabic-body, --hel-font-arabic-heading | The Arabic fonts. |
--hel-font-fallback | The list tried last. |
--brand-font-family-body, --brand-font-family-headings | The final stacks, in the order of the direction. |