PluginBench
Skill
Pass
Audit score 90

react

lobehub/lobe-chat

LobeHub React component conventions for TSX UI, styling, routing, and state management.

What is react?

Reference guide for writing React components in LobeHub projects. Use when editing TSX files, choosing between component libraries (@lobehub/ui/base-ui vs @lobehub/ui vs antd), applying styles with antd-style, setting up routing with react-router-dom, or managing component state.

  • Defines component priority hierarchy: project components → base-ui headless primitives → @lobehub/ui higher-level components → antd → custom implementation
  • Specifies styling approach: createStaticStyles + cssVar for most cases, inline styles for simple one-offs, createStyles + token only for truly dynamic values
  • Provides routing patterns using react-router-dom for SPA pages and Next.js App Router for auth pages, with desktop variant sync rules
  • Documents state management: extract logic into custom hooks when a component has more than 3 pieces of state
  • Lists preferred components from @lobehub/ui/base-ui (Select, Modal, DropdownMenu, ContextMenu, Popover, ScrollArea, Switch, Toast, FloatingSheet) with correct import paths
  • Specifies layout approach using Flexbox and Center from @lobehub/ui with gap-based spacing and overflow handling

How to install react

npx skills add https://github.com/lobehub/lobe-chat --skill react
Claude Code
Cursor
Windsurf
Cline

How to use react

  1. 1.When editing a TSX file, check the component priority table to select the correct import source (base-ui first, then @lobehub/ui, then antd)
  2. 2.For styling, use createStaticStyles + cssVar at module level unless the style is a simple one-off (inline style) or requires dynamic JS functions (createStyles + token)
  3. 3.If a component manages more than 3 pieces of state, extract the logic into a custom hook named useXxx to keep rendering logic separate
  4. 4.For layout, use Flexbox and Center from @lobehub/ui with gap for spacing between children instead of margin
  5. 5.For SPA navigation, import Link and useNavigate from react-router-dom, not next/link
  6. 6.After editing any .ts/.tsx file, check for a .desktop.ts(x) variant in the same directory and apply equivalent sync changes to prevent Electron blank pages

Use cases

Good for
  • Choosing the correct component library when building a new UI element to avoid importing antd directly
  • Styling a component with zero-runtime overhead using createStaticStyles and CSS variables
  • Refactoring a component with multiple useState calls into a custom hook for better testability
  • Setting up routing for a new SPA page using react-router-dom instead of next/link
  • Syncing changes between base web files and .desktop.tsx variants to prevent blank pages in Electron
Who it's for
  • React/TypeScript developers working on LobeHub projects
  • Frontend engineers building or maintaining TSX UI components
  • Developers new to the LobeHub codebase who need component and styling conventions
  • Teams maintaining both web and Electron desktop variants

react FAQ

Should I use antd Select or @lobehub/ui Select?

Use @lobehub/ui/base-ui Select. The root @lobehub/ui export wraps antd and is not the headless primitive; importing from @lobehub/ui/base-ui gives you the correct component.

When should I use createStyles instead of createStaticStyles?

Only when you need truly dynamic values computed at runtime using JS color functions like readableColor or chroma. For all other cases, use createStaticStyles + cssVar at module level for zero-runtime overhead.

What should I use instead of antd Spin for loading indicators?

Use project-specific loaders like NeuralNetworkLoading or DotsLoading. See the ux skill for the full component table and guidance on which loader to use for each scenario.

How do I handle routing in LobeHub projects?

Use react-router-dom (Link, useNavigate) for SPA pages in desktopRouter.config.tsx. Use Next.js App Router only for auth pages in src/app/[variants]/(auth)/. Never use next/link in the SPA.

What happens if I don't sync .desktop.tsx files after editing the base file?

The Electron desktop variant will have stale imports and logic, causing blank pages or broken functionality. Always glob for <filename>.desktop.{ts,tsx} in the same directory and apply equivalent changes.

Full instructions (SKILL.md)

Source of truth, from lobehub/lobe-chat.


name: react description: 'LobeHub React component conventions. Use when editing TSX UI, choosing base-ui vs @lobehub/ui vs antd, styling with antd-style, routing, desktop variants, layouts, or component state.' user-invocable: false

React Component Writing Guide

Styling

ScenarioApproach
Most casescreateStaticStyles + cssVar.* (zero-runtime, module-level)
Simple one-offInline style attribute
Truly dynamic (JS color fns like readableColor/chroma)createStyles + token — last resort

Component Priority

  1. src/components — project-specific reusable components
  2. @lobehub/ui/base-ui — headless primitives. If the component lives here, use it. Do NOT import the same-named root export.
  3. @lobehub/ui — higher-level / antd-wrapping components (only when no base-ui equivalent)
  4. antd — only when neither base-ui nor @lobehub/ui root provides it
  5. Custom implementation — true last resort

If unsure about available components, search existing code or check node_modules/@lobehub/ui/es/index.mjs and node_modules/@lobehub/ui/es/base-ui/.

@lobehub/ui/base-ui — always prefer for these

ComponentImport
Select (+ SelectProps, SelectOption)import { Select } from '@lobehub/ui/base-ui';
Modal (imperative API)import { createModal, confirmModal, useModalContext, type ModalInstance } from '@lobehub/ui/base-ui';
DropdownMenuimport { DropdownMenu } from '@lobehub/ui/base-ui';
ContextMenuimport { ContextMenu } from '@lobehub/ui/base-ui';
Popoverimport { Popover } from '@lobehub/ui/base-ui';
ScrollAreaimport { ScrollArea } from '@lobehub/ui/base-ui';
Switchimport { Switch } from '@lobehub/ui/base-ui';
Toastimport { Toast } from '@lobehub/ui/base-ui';
FloatingSheetimport { FloatingSheet } from '@lobehub/ui/base-ui';

For Modal specifically, see the dedicated modal skill — use the imperative createModal({ content: … }) pattern over the legacy <Modal open … /> declarative pattern. base-ui has its own ModalHost already mounted in SPAGlobalProvider.

Common slip: import { Select } from '@lobehub/ui' looks fine but it's the antd-backed Select. Use base-ui Select. Same for Modal, DropdownMenu, etc.

@lobehub/ui root — use when base-ui has no equivalent

CategoryComponents
GeneralActionIcon, ActionIconGroup, Block, Button, Icon
Data DisplayAvatar, Collapse, Empty, Highlighter, Markdown, Tag, Tooltip
Data EntryCodeEditor, CopyButton, EditableText, Form, Input, InputPassword, SearchBar, TextArea
FeedbackAlert, Drawer
LayoutCenter, DraggablePanel, Flexbox, Grid, Header, MaskShadow
NavigationBurger, Menu, SideNav, Tabs

Loading indicators

Do NOT use antd Spin / <Spin />. Use a project loader (NeuralNetworkLoading, DotsLoading, …) — see the ux skill ("Loading visuals") for the component table and when to use each.

State

When a feature component manages more than 3 pieces of state (useState/useReducer/derived state), extract the logic into a custom hook (e.g. useXxx). Keep the component focused on rendering — the hook holds state and handlers, so logic can be unit-tested without rendering the component.

Layout

Use Flexbox and Center from @lobehub/ui. See references/layout-kit.md for full props and examples.

  • Use gap instead of margin for spacing between flex children
  • Use flex={1} to fill available space
  • Nest Flexbox for complex layouts; set overflow: 'auto' for scrollable regions

Navigation

For SPA pages, use react-router-dom, NOT next/link.

// ❌ Wrong
import Link from 'next/link';

// ✅ Correct
import { Link, useNavigate } from 'react-router-dom';

Access navigate from stores: useGlobalStore.getState().navigate?.('/settings');

Desktop File Sync Rule

Files with a .desktop.ts(x) variant must be edited in sync. Drift causes blank pages in Electron.

Base file (web)Desktop file (Electron)
desktopRouter.config.tsxdesktopRouter.config.desktop.tsx
componentMap.tscomponentMap.desktop.ts

After editing any .ts/.tsx: glob for <filename>.desktop.{ts,tsx} in the same directory. If found, apply the equivalent sync-import change.

Routing Architecture

Route TypeUse CaseImplementation
Next.js App RouterAuth pagessrc/app/[variants]/(auth)/
React Router DOMMain SPAdesktopRouter.config.tsx + .desktop.tsx (pair)

Router utilities:

import { dynamicElement, redirectElement, ErrorBoundary } from '@/utils/router';
element: dynamicElement(() => import('./chat'), 'Desktop > Chat');
element: redirectElement('/settings/profile');
errorElement: <ErrorBoundary />;

Common Mistakes

MistakeFix
Using next/link in SPAUse react-router-dom Link
Using antd directlyUse @lobehub/ui/base-ui first, then @lobehub/ui
antd Spin / <Spin /> for loadingUse NeuralNetworkLoading / project loaders (see the ux skill)
import { Select } from '@lobehub/ui'import { Select } from '@lobehub/ui/base-ui'
import { Modal } from '@lobehub/ui' + <Modal open> declarativecreateModal / confirmModal from @lobehub/ui/base-ui (see modal skill)
import { DropdownMenu/Popover/Switch } from '@lobehub/ui'Import same name from @lobehub/ui/base-ui instead
createStyles for static stylesUse createStaticStyles + cssVar
Editing only desktopRouter.config.tsxMust edit both .tsx and .desktop.tsx
Using margin for flex spacingUse gap prop on Flexbox
Accessing zustand store without selectorUse selectors to access store data (see zustand skill)
Text or icon-text actions built with Flexbox/Text + onClickUse Button type={'text'} size={'small'} with icon when needed