# What Programming Languages and Frameworks Power AFFiNE's Frontend?

> Discover the frontend tech stack of AFFiNE, a powerful collaborative editor. Learn about the programming languages and frameworks like TypeScript, React 19, Radix UI, and Jotai powering its interface.

- Repository: [Toeverything/AFFiNE](https://github.com/toeverything/AFFiNE)
- Tags: technology-stack
- Published: 2026-03-05

---

**AFFiNE's frontend is built with TypeScript and React 19, utilizing Radix UI primitives, Blocksuite for document editing, Jotai for state management, and a hybrid styling approach using Emotion and Vanilla-Extract.**

AFFiNE is an open-source knowledge management platform that unifies documents, whiteboards, and databases in a collaborative workspace. Understanding the programming languages and frameworks used in AFFiNE's frontend reveals how the application delivers high-performance, real-time collaborative editing across web and desktop platforms.

## Core Language and UI Foundation

### TypeScript as the Primary Language

The entire frontend codebase is written in **TypeScript** (with TSX for React components), providing static type safety and excellent IDE support. This choice enables robust refactoring across the monorepo structure and ensures type consistency between the React UI layer and the underlying data models.

### React 19 for Component Rendering

At the heart of the UI lies **React 19** (specifically version 19.2.1 as defined in [`packages/frontend/core/package.json`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/package.json)). The application leverages React's concurrent features and modern hooks architecture to manage complex rendering scenarios, including real-time collaborative cursors and large document trees.

## Component Architecture and Design System

### Radix UI for Accessible Primitives

AFFiNE builds its component layer on **Radix UI** primitives (`@radix-ui/react-dialog`, `@radix-ui/react-collapsible`, etc.). These unstyled, accessible components provide the behavioral foundation for custom UI elements like modals, dropdown menus, and toolbars without imposing specific visual designs.

### Blocksuite for Document and Canvas Editing

The rich-text editing and whiteboard capabilities come from **Blocksuite**, AFFiNE's custom framework (`@blocksuite/affine`, `@blocksuite/std`, `@blocksuite/icons`). Blocksuite implements a CRDT-based document model that powers the collaborative editor, draggable canvas elements, and block-based content structure. Integration points reside in `packages/frontend/core/src/modules/**/view/**/*.tsx`.

## State Management and Reactivity

### Jotai for Global State

Global application state (workspaces, user preferences, navigation history) is managed using **Jotai** atoms (`jotai`, `jotai-scope`). This atomic approach allows fine-grained subscription to state changes, preventing unnecessary re-renders in complex UI trees. State definitions are centralized in `packages/frontend/core/src/store/**`.

### Preact Signals for High-Frequency Updates

For performance-critical scenarios requiring ultra-fast reactivity (drag-and-drop coordinates, animation states, real-time cursor positions), AFFiNE incorporates **Preact Signals** (`@preact/signals-core`). Signals provide synchronous, fine-grained updates that bypass React's render cycle when necessary.

Example implementation combining both approaches:

```tsx
import { atom, useAtom } from 'jotai';
import { signal } from '@preact/signals-core';

const countAtom = atom(0);
const countSignal = signal(0);

export const Counter = () => {
  const [count, setCount] = useAtom(countAtom);
  const inc = () => {
    setCount(c => c + 1);
    countSignal.value += 1;
  };
  return <button onClick={inc}>Clicked {count} ({countSignal.value}) times</button>;
};

```

## Styling Architecture

AFFiNE employs a **hybrid styling strategy** that combines multiple CSS-in-JS solutions to balance developer experience and runtime performance:

- **Emotion** (`@emotion/react`): Used for dynamic, theme-dependent styles that require JavaScript runtime evaluation. Powers component-specific styling that reacts to state changes.
- **Vanilla-Extract** (`@vanilla-extract/*`): Provides zero-runtime, type-safe CSS extraction. Used for static design tokens and component styles that don't require dynamic computation.
- **TailwindCSS**: Utilized specifically for the admin UI panels, offering utility-first rapid development for internal tools.

Theme configuration files reside in `packages/frontend/core/src/styles/**`.

## Routing and Theming

### React Router 6 for Navigation

Client-side routing is handled by **React Router 6** (`react-router-dom` v6.30.3), configured in [`packages/frontend/apps/web/src/router.tsx`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/apps/web/src/router.tsx). The router manages deep linking to specific documents, workspace switching, and modal routing.

### next-themes for Color Schemes

Light and dark mode support is implemented using **next-themes** (`next-themes`), integrated in [`packages/frontend/apps/web/src/theme-toggle.tsx`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/apps/web/src/theme-toggle.tsx). The theme provider manages system preference detection and manual theme toggling.

```tsx
import { useTheme } from 'next-themes';
import { useEffect } from 'react';

export const ThemeToggle = () => {
  const { setTheme, resolvedTheme } = useTheme();
  useEffect(() => {
    document.body.dataset.theme = resolvedTheme;
  }, [resolvedTheme]);
  return <button onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}>Toggle</button>;
};

```

## Key Implementation Files

The following files illustrate how these frameworks integrate in the AFFiNE codebase:

| Area | File Path | Purpose |
|------|-----------|---------|
| **Dependencies** | [`packages/frontend/core/package.json`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/package.json) | Declares React 19, Radix UI, Blocksuite, Jotai, and styling libraries |
| **Bootstrap** | [`packages/frontend/core/src/bootstrap/index.ts`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/src/bootstrap/index.ts) | React application entry point and provider composition |
| **Routing** | [`packages/frontend/apps/web/src/router.tsx`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/apps/web/src/router.tsx) | React Router 6 configuration |
| **Components** | `packages/frontend/component/src/**` | Reusable UI primitives built on Radix |
| **Editor Integration** | `packages/frontend/core/src/modules/**/view/**/*.tsx` | Blocksuite editor and canvas components |
| **State** | `packages/frontend/core/src/store/**` | Jotai atoms and signal definitions |
| **Styling** | `packages/frontend/core/src/styles/**` | Emotion themes and Vanilla-Extract style files |
| **Electron** | `packages/frontend/electron-api/src/**` | Desktop-specific API bridge |

## Summary

- **AFFiNE's frontend** is built primarily with **TypeScript** and **React 19**, leveraging modern concurrent features for high-performance UI rendering.
- The component architecture combines **Radix UI** primitives for accessibility with **Blocksuite** for rich-text and canvas editing capabilities.
- State management uses a dual approach: **Jotai** for global application state and **Preact Signals** for high-frequency reactive updates.
- Styling employs a hybrid strategy with **Emotion** for dynamic styles, **Vanilla-Extract** for zero-runtime CSS, and **TailwindCSS** for admin interfaces.
- The application uses **React Router 6** for navigation and **next-themes** for theme management, with specific implementations found in [`packages/frontend/core/package.json`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/core/package.json) and related source files.

## Frequently Asked Questions

### Is AFFiNE's frontend built with Next.js?

No, AFFiNE does not use Next.js as its primary framework. While the project includes `next-themes` for theme management, the core frontend is a **React 19** single-page application built with **React Router 6** for client-side routing, as seen in [`packages/frontend/apps/web/src/router.tsx`](https://github.com/toeverything/AFFiNE/blob/main/packages/frontend/apps/web/src/router.tsx).

### What is Blocksuite and how does it relate to AFFiNE?

**Blocksuite** is AFFiNE's custom rich-text and canvas editing framework (`@blocksuite/affine`). It provides the CRDT-based document model, block-based content structure, and collaborative editing capabilities that power AFFiNE's note-taking and whiteboard features. The integration code resides in `packages/frontend/core/src/modules/**/view/**/*.tsx`.

### Why does AFFiNE use both Jotai and Preact Signals?

AFFiNE uses **Jotai** for global application state (workspaces, settings) where React's lifecycle integration is beneficial, and **Preact Signals** (`@preact/signals-core`) for high-frequency updates (drag-and-drop coordinates, animations) that require synchronous, fine-grained reactivity outside of React's render cycle. This dual approach optimizes performance for different interaction patterns.

### How is styling handled across different parts of the AFFiNE frontend?

The frontend employs a **hybrid styling architecture**: **Emotion** handles dynamic, theme-dependent styles at runtime; **Vanilla-Extract** provides zero-runtime, type-safe CSS for static design tokens; and **TailwindCSS** is used specifically for the admin UI panels. This approach balances developer experience with runtime performance across different application surfaces.