raystack / raystack/apsara

Remove font loading from the library; let apps load their own fonts

Open
#855 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

BREAKING CHANGE enhancement global
Dominant language
TypeScript
Stars
70
Forks
13
Avg merge
2d 5h
Merged PRs (30d)
8

Description

Summary

The library loads fonts itself. packages/raystack/styles/typography.css starts with four Google Fonts @import calls:

@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Lora:wght@400;500&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;500&display=swap");
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital@0;1&display=swap");

A component library should not decide how or where fonts load. That belongs to the app. We should remove these imports and keep only the --rs-font-* variables (the font-family names), then let each app load the fonts it needs.

Why this is a problem

  • Consumers download fonts they never use. Any app that pulls in Apsara fetches Inter, Lora, Josefin Sans, and JetBrains Mono — even if it only uses Inter. Lora and Josefin Sans only apply under [data-style="traditional"], so most apps pay for them for nothing.
  • @import blocks render. Fonts inside a CSS @import are found late by the browser, which delays paint and causes a flash of unstyled text (FOUT).
  • Extra connections. Each @import needs DNS + TLS to Google's domains before the font even downloads.
  • No control for the app. The app can't preload the font, can't set font-display, and can't self-host. All of that is decided inside the library.
  • Blocks other improvements. We can't cleanly add a 600 weight or use Inter's optical-sizing (opsz) axis, because the library pins the exact Google Fonts URL and weights.

Proposal

  1. Remove the four @import lines from packages/raystack/styles/typography.css.
  2. Keep the --rs-font-* variables (Inter, Lora, Josefin Sans, JetBrains Mono, Menlo) so component styles stay unchanged.
  3. Document how consuming apps load the fonts, for example:
    • Self-host with Fontsource — @fontsource-variable/inter (variable font, all weights from one file).
    • next/font for Next.js apps.
    • A plain @font-face or Google Fonts <link> for apps that want it.
  4. Note the optional families (Lora, Josefin Sans) are only needed for the traditional style.

Breaking change

This is a breaking change. Apps that rely on Apsara loading fonts will render in a fallback font until they load the fonts themselves. The migration is small — install the fonts and import them once at the app entry — but it must be called out in release notes with a clear before/after.

Acceptance criteria

  • No @import of font files in the library CSS.
  • --rs-font-* variables still present; components render identically once the app loads Inter.
  • Docs / README show how to load fonts in a plain Vite app and a Next.js app.
  • Migration note added to the changelog / release notes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/raystack/styles/typography.css and verify the --rs-font-* variables that must remain. Then locate the project README or docs and changelog/release notes entry points mentioned in the issue, and check the existing package guidance for Vite and Next.js. Done means the font imports are gone, usage guidance covers both app types, optional traditional-style fonts are noted, and the breaking-change migration is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, next.js, react, vite
Domain
documentation, frontend, release
Issue type
Refactor
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.