実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。
- 変更後の製品動作を実地で検証したいとき
- 画面キャプチャなどの証拠を集めたいとき
- 検証計画とレポートを作成したいとき
Reactのコンポーネント設計やスタイル選択、状態の置き場所、レイアウト、再描画の最適化について、既存のUI構成に沿った実装方針を示します。
Use for TSX components, UI libraries, styling, state locality, layout, render performance and memoization.
実行スコア 未検証
インストール方法を見るReactやTSXで画面を実装するときに、既存のUIライブラリから使う部品を選び、スタイル、状態、レイアウトを整理するためのガイドです。StyleXへの移行方針や、移行時にスタイル差分を確認する方法も扱います。状態は必要な範囲で最も小さな所有者に置き、再利用や更新境界などの理由があるときにコンポーネントを分割します。memo、useMemo、useCallbackは既定で付けず、実際に避けられる処理を確認してから使う考え方を示します。
新しい画面部品を作るとき、既存のコンポーネントやスタイル規約に合わせたい場合に役立ちます。状態をどこに持たせるか迷うときや、描画が重い箇所を調べて最適化したいときにも参照できます。複雑なレイアウトではFlexboxやCenterの使い方を確認できます。
記載された部品や移行手順は@lobehub/ui、StyleXなどプロジェクト固有の構成に基づきます。詳細なレイアウト例はreferences/layout-kit.mdを参照します。
この紹介文は、公開されている SKILL.md をもとに AI(OpenAI Codex)が作成しました。正確な仕様は下の原文を確認してください。
SKILL.md の記述から、注意が要る操作と導入の前提を AI が確認しました。点数は実際に動かした結果(実行検証)だけで付けています。
点数には入れていません。 2026年10月26日 時点で AI(OpenAI Codex)が判定しました。目安なので、入れる前に原文も確認してください。
インストールする前に、エージェントに与えられる指示の中身を確認できます。
| Scenario | Approach |
|---|---|
| Files already on StyleX, and new SPA styles | stylex.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 migrated | createStaticStyles + cssVar.* (zero-runtime, module-level) |
| Simple one-off | Inline style attribute |
Truly dynamic (JS color fns like readableColor/chroma) | createStyles + token — last resort |
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..x:not(#\#)) and beat emotion classes on the same element, but StyleX shorthand rules do not, so a half-migrated element resolves by property.className / style: {...sx([styles.root, active && styles.active], className, style)} from @/styles/sx. Spreading stylex.props next to className fails @stylexjs/no-conflicting-props.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.@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.__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).src/components — project-specific reusable components@lobehub/ui/base-ui — headless primitives. If the component lives here, use it. Do NOT import the same-named root export.@lobehub/ui — higher-level / antd-wrapping components (only when no base-ui equivalent)@lobehub/ui root provides itIf 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| Component | Import |
|---|---|
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'; |
DropdownMenu | import { DropdownMenu } from '@lobehub/ui/base-ui'; |
ContextMenu | import { ContextMenu } from '@lobehub/ui/base-ui'; |
Popover | import { Popover } from '@lobehub/ui/base-ui'; |
ScrollArea | import { ScrollArea } from '@lobehub/ui/base-ui'; |
Switch | import { Switch } from '@lobehub/ui/base-ui'; |
Toast | import { Toast } from '@lobehub/ui/base-ui'; |
FloatingSheet | import { FloatingSheet } from '@lobehub/ui/base-ui'; |
Drawer | import { 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 forModal,DropdownMenu, etc.
@lobehub/ui root — use when base-ui has no equivalent| Category | Components |
|---|---|
| General | ActionIcon, ActionIconGroup, Block, Button, Icon |
| Data Display | Avatar, Collapse, Empty, Highlighter, Markdown, Tag, Tooltip |
| Data Entry | CodeEditor, CopyButton, EditableText, Form, Input, InputPassword, SearchBar, TextArea |
| Layout | Center, DraggablePanel, Flexbox, Grid, Header, MaskShadow |
| Navigation | Burger, Menu, SideNav, Tabs |
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.
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).
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.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.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:
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.
Use Flexbox and Center from @lobehub/ui. See references/layout-kit.md for full props and examples.
gap instead of margin for spacing between flex childrenflex={1} to fill available spaceoverflow: 'auto' for scrollable regionsux: 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.まだレビューはありません。使ってみた感想をお寄せください。
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。
実際の製品を操作して、利用者が確認できる動作証拠を集め、検証計画に沿った受け入れレポートとして公開するスキルです。
LobeHubにAIモデルプロバイダーを追加し、実行時連携からモデル表示、設定、ブランド表記、文書化、動作確認まで進めるスキルです。
ユーザー設定の初期値をサーバー側の環境変数で切り替えるため、型定義や設定の組み立て、ユーザーストアへの反映、環境変数の例と説明書きを追加する手順です。
エージェント実行中の各段階をフックで監視し、ツール呼び出しの模擬・制御や人の承認、圧縮、サブエージェント処理に介入する仕組みを扱います。
イベントを起点にエージェントのバックグラウンド処理を組み立て、ソース・シグナル・アクション・ポリシーの役割分担や非同期連携を実装するためのスキルです。
DiscordやSlackなどの実際のチャットアプリでボットにメッセージを送り、応答を画面で確認する受け入れテストを行うスキルです。