Skip to content
cccskills
FreePublished on GitHubEnglish overview

react

Use this guide when building React and TSX components. It explains how to choose UI components and styling, place state, structure layouts, and decide when memoization is justified, with conventions for the project’s UI libraries.

OriginalShow the original description

Use for TSX components, UI libraries, styling, state locality, layout, render performance and memoization.

lobehub/lobehub83,502 stars(GitHub 83,502 + cccskills 0)

Run score Not tested

See how to install

Good for

  • Choosing components from the project’s UI libraries
  • Styling a new or existing React component
  • Deciding where transient state should live
  • Reviewing whether memoization is justified

Overview

What it does

This guide helps you build screens with React or TSX while following the project’s existing UI libraries and styling conventions. It explains how to choose components, organize styles and layouts, and keep state with the smallest component that needs it. It also covers the project’s approach to moving styles to StyleX and checking visual differences during a migration. For rendering performance, it recommends adding memo, useMemo, or useCallback only after identifying work they can actually prevent. Components should be split when reuse or update boundaries give a clear reason.

When it helps

Use it when creating a screen component that should fit the existing UI patterns, deciding where state belongs, or investigating a slow render. For complex layouts, it explains how to use Flexbox and Center.

Example requests

  • “Implement this TSX screen using the existing UI components and styling conventions.”
  • “Help decide whether this state belongs in the parent or child, including where to split the components.”
  • “Check the update path and tell me whether memoization would help this re-render.”

Notes

The component choices and migration steps are based on project-specific setup such as @lobehub/ui and StyleX. Detailed layout examples are in references/layout-kit.md.

This overview was written by AI (OpenAI Codex) from the public SKILL.md. Check the original below for the exact behavior.

Document check

AI checked the SKILL.md for operations that need care and for setup requirements. The score comes only from actually running the skill (hands-on test).

SafetyAre sending data, deleting files, and running commands disclosed?
BPartly lackingMigration checks use `git stash`; safeguards around that workflow are limited.
Easy setupDoes it need few tools or API keys, and are they documented?
BPartly lackingIt assumes Bun, StyleX, and project UI libraries, without setup instructions.

Not counted in the score. Rated by AI (OpenAI Codex) as of Oct 26, 2026. Treat it as a guide and read the original before installing.

Disagree? Request a re-evaluation

Tell us which point is wrong and why. No login needed. We will check it against the SKILL.md, redo the evaluation, and show the result here.

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

Files included (2)

  • SKILL.md11.6 KB
  • references/layout-kit.md2.3 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

React Component Writing Guide

Styling

ScenarioApproach
Files already on StyleX, and new SPA stylesstylex.create + @lobehub/ui/stylex/cssVar.stylex / @lobehub/ui/stylex/media.stylex. The SPA compiler is plugins/vite/stylex.ts (@stylexjs/unplugin, prefix lh). Do not copy those token modules into the app.
Existing styles not yet migratedcreateStaticStyles + cssVar.* (zero-runtime, module-level)
Simple one-offInline style attribute
Truly dynamic (JS color fns like readableColor/chroma)createStyles + token — last resort

StyleX

  • New code may not import createStaticStyles / createStyles / css / keyframes / createGlobalStyle / injectGlobal from @lobehub/ui (stylex-migration/no-emotion-styles). Files still on them are listed in scripts/stylexMigration/legacyFiles.json; after migrating one, run bun run stylex:migration --prune-legacy. Never add entries.
  • Migrate a whole file at once. StyleX longhand rules carry raised specificity (.x:not(#\#)) and beat emotion classes on the same element, but StyleX shorthand rules do not, so a half-migrated element resolves by property.
  • Element that also forwards a caller's className / style: {...sx([styles.root, active && styles.active], className, style)} from @/styles/sx. Spreading stylex.props next to className fails @stylexjs/no-conflicting-props.
  • Component that lets callers restyle it: take xstyle?: StyleXStyles and pass it last in the sx / stylex.props array. A plain className from outside cannot override StyleX rules. Passing a class to @lobehub/ui components (className, classNames) works, because lobe-ui CSS sits in @layer lobe-ui.
  • Values follow @stylexjs/valid-styles: no multi-value shorthands (margin: '0 8px' → marginBlock / marginInline), and string flex (flex: '1').
  • background, animation, border and border{Top,Right,Bottom,Left} shorthands compile to no class at all, whatever the value (border: 'none' included), without an error. Write longhands: backgroundColor (plus backgroundImage: 'none' when replacing a background shorthand), animationName / animationDuration / …, borderWidth / borderStyle / borderColor.
  • Check a migration in dev with the DevDock snapshot helper: on the migrated page run __lobeStyleSnapshot.capture('<name>', '<root selector>'), swap the files back (git stash push -- <path>), reload, run __lobeStyleSnapshot.compare('<name>'), then git stash pop. Each pair reads [captured, current], here [migrated, original]. It lists elements and ::before / ::after whose tracked computed styles, box (relative to the root) or text differ; an empty list means those match, not that hover, focus or closed dialogs were checked, so open each state you migrated and compare it too. Keep the window size, scroll everything under the root back to the start, and move the pointer off the compared area.
  • bun run stylex:migration --list <A|B|C|D> lists files by how hard they are to move: A flat, B self pseudo-classes, C descendant / ancestor coupling (use stylex.defaultMarker() + stylex.when.ancestor() or xstyle), D tag / third-party DOM selectors (scoped plain CSS).

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
Alert (+ AlertProps)import { Alert, type AlertProps } from '@lobehub/ui/base-ui';
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';
Drawerimport { Drawer } 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
LayoutCenter, DraggablePanel, Flexbox, Grid, Header, MaskShadow
NavigationBurger, Menu, SideNav, Tabs

State

Keep transient state in its smallest useful owner. Extract a custom hook when state transitions and handlers obscure rendering or form a reusable unit; do not extract solely because a component has a particular number of hooks.

Split a component only to establish a real state, reuse, render-update, or mountable-capability boundary. Do not split solely to make files smaller; when a file reaches the 1200-line limit in source-layout, find one of these boundaries rather than cutting at a line count. Decomposing a heavy domain feature into host-assembled atoms is owned by compose-atoms.

Popover Exits

An action inside popover content that leaves the popover must close it, or the popover stays over the destination (for example, a plan badge in the user panel navigating to /settings/plans).

  • Navigation: a host whose content links or navigates keeps open state, calls useCloseOnNavigate(open, () => setOpen(false)) from @/hooks/useCloseOnNavigate, and passes the returned key to its Popover. This covers links added later, including links from other files. The key matters when navigation hides the host in an <Activity> (the home sidebar): a hidden tree sets up no new effects, so the base-ui popup never finishes its exit animation and stays on screen until a remount removes it.
  • Modal handoff or a final pick: call usePopoverContext().close() (or the host's setter) before opening the modal or after the pick, as NavPanel/switcher/SwitcherMenu.tsx does. Content rendered outside a popover cannot use the context, because its default close throws in development.
  • A confirm step whose result appears in the same popover, such as the share-link privacy confirm, keeps it open.

Render Performance and Memoization

Treat memo, useMemo, and useCallback as opt-in optimizations, not default component wrappers. Before adding one, identify the actual rerender boundary and prefer structural fixes:

  1. Split at the update boundary.
  2. Move transient state to its smallest owner.
  3. Use narrow Zustand selectors and avoid broad subscriptions.

Do not memoize prop-free or trivially rendered components, or a component that normally receives new objects, arrays, functions, or JSX children. Do not use memoization to compensate for state held too high in the tree.

Use memoization only when the subtree is demonstrably expensive or frequently repeated, its relevant inputs are stable during normal parent renders, and profiling or a concrete render-path analysis identifies the avoided work. State that reason in the implementation summary or PR.

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

Related Skills

  • ux: loading visuals (scenario → loader table in references/feedback.md §4.1) and user-facing interaction design.
  • modal: imperative base-ui modal patterns.
  • spa-routes: SPA navigation, route ownership, router configuration, and .desktop variants.
  • compose-atoms: split a heavy domain feature into mountable capability atoms; each host imports only what it mounts.
  • zustand: store structure and selector conventions.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

acceptance

FreeSummary

Use this skill to verify a delivery by exercising the real product through a suitable surface such as a CLI, web app, desktop app, or iOS Simulator. It helps create or find a verification plan, capture evidence, and publish an acceptance report.

  • Verifying a completed product change
  • Collecting screenshots or other evidence
  • Creating a verification plan and report
lobehub/lobehub83.5KUpdated Oct 26, 2026

Use this skill to add an AI model provider to LobeHub across runtime integration, model cards, settings, branding, documentation, and acceptance checks. It also covers provider documentation updates and distinguishes new providers from models added to an existing provider.

  • Integrating a new AI model provider into LobeHub
  • Updating setup or usage documentation for a provider
  • Checking whether a model needs a new provider integration
lobehub/lobehub83.5KUpdated Oct 26, 2026

add-setting-env

FreeSummary

Use this skill to add a server-side environment variable that sets a default for a user setting. It walks through validation, server configuration and store merging, plus updating the example environment file and self-hosting documentation.

  • Adding an environment variable for a setting default
  • Wiring a new setting domain into server config
  • Documenting a new variable for self-hosting
lobehub/lobehub83.5KUpdated Oct 26, 2026

Provides guidance for registering hooks around an agent’s execution steps, tool calls, human approvals, context compression, and sub-agent calls. Hooks can observe events, supply local mock tool results, or use webhooks to allow or deny tool results under configured policies.

  • Observing agent steps and tool errors
  • Mocking tool results during local execution
  • Requiring webhook decisions before or after a tool call
lobehub/lobehub83.5KUpdated Oct 26, 2026

agent-signal

FreeSummary

Build event-driven background workflows for agents by defining sources, interpreting them as signals, and running actions through policies. It also guides asynchronous handoffs, deduplication, scoped execution, completion receipts, and observability.

  • Adding a new event source to an agent workflow
  • Routing interpreted signals to concrete background actions
  • Enqueuing work for asynchronous processing
lobehub/lobehub83.5KUpdated Oct 26, 2026

Use this skill to run end-to-end acceptance checks for bot channels in real desktop chat apps. It drives apps such as Discord, Slack, Telegram, WeChat, Lark, and QQ to send a message, wait for a response, and capture the result.

  • Checking a bot response in a real Discord channel
  • Testing chat behavior through Slack or Telegram
  • Capturing a bot interaction in a native macOS app
lobehub/lobehub83.5KUpdated Oct 26, 2026

See all skills by lobehub

Report a problem with this skill