ui-ux-consultant-cli 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/ui-ux-consultant/SKILL.md +844 -0
- package/assets/ui-ux-consultant/references/accessibility.md +175 -0
- package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
- package/assets/ui-ux-consultant/references/animations.md +448 -0
- package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
- package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
- package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
- package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
- package/assets/ui-ux-consultant/references/components.md +1116 -0
- package/assets/ui-ux-consultant/references/patterns.md +600 -0
- package/assets/ui-ux-consultant/references/performance.md +198 -0
- package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
- package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
- package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
- package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
- package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
- package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
- package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
- package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
- package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
- package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
- package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
- package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
- package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
- package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
- package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
- package/assets/ui-ux-consultant/references/theming.md +701 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/package.json +51 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# React UI/UX Guidelines
|
|
2
|
+
|
|
3
|
+
## When to read this
|
|
4
|
+
Read this file when building UI with React 18+ and hooks. Covers state management, rendering optimization, accessibility, and component patterns for modern React apps.
|
|
5
|
+
|
|
6
|
+
## Recommended UI Libraries
|
|
7
|
+
|
|
8
|
+
| Library | Best for | Install |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| shadcn/ui | Copy-paste accessible components | `npx shadcn@latest init` |
|
|
11
|
+
| Radix UI | Headless accessible primitives | `npm install @radix-ui/react-*` |
|
|
12
|
+
| React Hook Form | Performant forms | `npm install react-hook-form` |
|
|
13
|
+
| Zustand | Simple global state | `npm install zustand` |
|
|
14
|
+
| TanStack Query | Server state / data fetching | `npm install @tanstack/react-query` |
|
|
15
|
+
| Framer Motion | Animations | `npm install framer-motion` |
|
|
16
|
+
|
|
17
|
+
## Style Recommendations by App Type
|
|
18
|
+
|
|
19
|
+
- **Consumer SaaS:** Flat Design + Glassmorphism (shadcn/ui default theme)
|
|
20
|
+
- **Dashboard:** Data-Dense + Dark Mode
|
|
21
|
+
- **E-commerce:** Vibrant + Block-based
|
|
22
|
+
- **Developer tool:** Minimalist + Dark Mode First
|
|
23
|
+
|
|
24
|
+
## Top UX Patterns
|
|
25
|
+
|
|
26
|
+
### 1. Loading / Error / Data State Pattern
|
|
27
|
+
```jsx
|
|
28
|
+
const [data, setData] = useState(null);
|
|
29
|
+
const [loading, setLoading] = useState(true);
|
|
30
|
+
const [error, setError] = useState(null);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
fetch('/api/data')
|
|
34
|
+
.then(r => r.json())
|
|
35
|
+
.then(setData)
|
|
36
|
+
.catch(setError)
|
|
37
|
+
.finally(() => setLoading(false));
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
if (loading) return <Spinner />;
|
|
41
|
+
if (error) return <ErrorMessage error={error} />;
|
|
42
|
+
return <DataView data={data} />;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Optimistic Update
|
|
46
|
+
```jsx
|
|
47
|
+
async function toggleFavorite(id) {
|
|
48
|
+
const prev = items;
|
|
49
|
+
setItems(items.map(i => i.id === id ? { ...i, favorite: !i.favorite } : i));
|
|
50
|
+
try {
|
|
51
|
+
await api.toggle(id);
|
|
52
|
+
} catch {
|
|
53
|
+
setItems(prev);
|
|
54
|
+
toast.error('Update failed');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Debounced Search with useDeferredValue
|
|
60
|
+
```jsx
|
|
61
|
+
const [query, setQuery] = useState('');
|
|
62
|
+
const deferredQuery = useDeferredValue(query);
|
|
63
|
+
const filtered = useMemo(
|
|
64
|
+
() => items.filter(i => i.name.includes(deferredQuery)),
|
|
65
|
+
[items, deferredQuery]
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 4. Custom Data Fetching Hook
|
|
70
|
+
```jsx
|
|
71
|
+
function useFetch(url) {
|
|
72
|
+
const [state, setState] = useState({ data: null, loading: true, error: null });
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
setState(s => ({ ...s, loading: true }));
|
|
75
|
+
fetch(url)
|
|
76
|
+
.then(r => r.json())
|
|
77
|
+
.then(data => setState({ data, loading: false, error: null }))
|
|
78
|
+
.catch(error => setState({ data: null, loading: false, error }));
|
|
79
|
+
}, [url]);
|
|
80
|
+
return state;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 5. Context with Memoized Value
|
|
85
|
+
```jsx
|
|
86
|
+
const ThemeContext = createContext(null);
|
|
87
|
+
|
|
88
|
+
function ThemeProvider({ children }) {
|
|
89
|
+
const [theme, setTheme] = useState('light');
|
|
90
|
+
const value = useMemo(() => ({ theme, setTheme }), [theme]);
|
|
91
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function useTheme() {
|
|
95
|
+
const ctx = useContext(ThemeContext);
|
|
96
|
+
if (!ctx) throw new Error('useTheme must be used within ThemeProvider');
|
|
97
|
+
return ctx;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 6. Controlled Form with React Hook Form
|
|
102
|
+
```jsx
|
|
103
|
+
import { useForm } from 'react-hook-form';
|
|
104
|
+
|
|
105
|
+
function LoginForm() {
|
|
106
|
+
const { register, handleSubmit, formState: { errors } } = useForm();
|
|
107
|
+
const onSubmit = data => console.log(data);
|
|
108
|
+
return (
|
|
109
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
110
|
+
<input {...register('email', { required: 'Email is required' })} />
|
|
111
|
+
{errors.email && <span>{errors.email.message}</span>}
|
|
112
|
+
<button type="submit">Login</button>
|
|
113
|
+
</form>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 7. Lazy-Loaded Route Component
|
|
119
|
+
```jsx
|
|
120
|
+
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
|
|
121
|
+
|
|
122
|
+
function App() {
|
|
123
|
+
return (
|
|
124
|
+
<Suspense fallback={<PageSkeleton />}>
|
|
125
|
+
<Routes>
|
|
126
|
+
<Route path="/dashboard" element={<Dashboard />} />
|
|
127
|
+
</Routes>
|
|
128
|
+
</Suspense>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 8. Error Boundary
|
|
134
|
+
```jsx
|
|
135
|
+
class ErrorBoundary extends React.Component {
|
|
136
|
+
state = { hasError: false };
|
|
137
|
+
static getDerivedStateFromError() { return { hasError: true }; }
|
|
138
|
+
componentDidCatch(error, info) { logError(error, info); }
|
|
139
|
+
render() {
|
|
140
|
+
if (this.state.hasError) return <FallbackUI />;
|
|
141
|
+
return this.props.children;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Usage
|
|
145
|
+
<ErrorBoundary><FeatureComponent /></ErrorBoundary>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 9. Virtualized Long List
|
|
149
|
+
```jsx
|
|
150
|
+
import { FixedSizeList as List } from 'react-window';
|
|
151
|
+
|
|
152
|
+
function VirtualList({ items }) {
|
|
153
|
+
return (
|
|
154
|
+
<List height={600} itemCount={items.length} itemSize={60} width="100%">
|
|
155
|
+
{({ index, style }) => (
|
|
156
|
+
<div style={style}>
|
|
157
|
+
<ItemRow item={items[index]} />
|
|
158
|
+
</div>
|
|
159
|
+
)}
|
|
160
|
+
</List>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 10. Focus Management for Modal
|
|
166
|
+
```jsx
|
|
167
|
+
function Modal({ isOpen, onClose, children }) {
|
|
168
|
+
const firstFocusRef = useRef(null);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (isOpen) firstFocusRef.current?.focus();
|
|
171
|
+
}, [isOpen]);
|
|
172
|
+
return isOpen ? (
|
|
173
|
+
<div role="dialog" aria-modal="true">
|
|
174
|
+
<button ref={firstFocusRef} onClick={onClose} aria-label="Close">X</button>
|
|
175
|
+
{children}
|
|
176
|
+
</div>
|
|
177
|
+
) : null;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Best Practices by Category
|
|
182
|
+
|
|
183
|
+
### State
|
|
184
|
+
- `useState` for local component state
|
|
185
|
+
- `useReducer` for complex state with multiple sub-values or transition logic
|
|
186
|
+
- Lift shared state to the nearest common ancestor
|
|
187
|
+
- Compute derived values in render — do not store them in state
|
|
188
|
+
- Lazy initialize expensive state: `useState(() => compute())`
|
|
189
|
+
|
|
190
|
+
### Components
|
|
191
|
+
- Small and focused — single responsibility per component
|
|
192
|
+
- Composition over inheritance
|
|
193
|
+
- Use fragments (`<>...</>`) to avoid extra DOM nodes
|
|
194
|
+
- Colocate related code (state, handlers, JSX) in the same file
|
|
195
|
+
- `React.memo` for pure components that receive stable props
|
|
196
|
+
|
|
197
|
+
### Rendering
|
|
198
|
+
- Stable keys: `item.id` not `index` on dynamic lists
|
|
199
|
+
- `useMemo` for expensive calculations — only when profiler confirms it helps
|
|
200
|
+
- `useCallback` for handlers passed as props to memoized children
|
|
201
|
+
- Avoid creating new objects or arrays inline in JSX — extract to variables
|
|
202
|
+
|
|
203
|
+
### Effects
|
|
204
|
+
- Always cleanup subscriptions: `return () => unsubscribe()`
|
|
205
|
+
- Correct deps array — eslint-plugin-react-hooks enforces this
|
|
206
|
+
- Do not use effects for derived data; compute in render
|
|
207
|
+
- `useRef` for mutable values that should not trigger re-renders
|
|
208
|
+
|
|
209
|
+
### Routing
|
|
210
|
+
- Use React Router v6 with `createBrowserRouter`
|
|
211
|
+
- Lazy-load all route components with `React.lazy`
|
|
212
|
+
- Use `<Suspense>` with a skeleton fallback per route
|
|
213
|
+
- Use `useNavigate` hook — not imperative `history.push`
|
|
214
|
+
|
|
215
|
+
### Performance
|
|
216
|
+
- `React.lazy` + `Suspense` for code splitting at route boundaries
|
|
217
|
+
- Virtualize long lists with react-window (> 100 items)
|
|
218
|
+
- Use React DevTools Profiler to find actual bottlenecks before optimizing
|
|
219
|
+
- Do not premature-optimize with `useMemo`/`useCallback` everywhere
|
|
220
|
+
|
|
221
|
+
### Forms
|
|
222
|
+
- Controlled components: `value` + `onChange` on all inputs
|
|
223
|
+
- `event.preventDefault()` on form submit handlers
|
|
224
|
+
- `useDeferredValue` for search input debounce
|
|
225
|
+
- Use React Hook Form for complex forms — avoids re-render on every keystroke
|
|
226
|
+
|
|
227
|
+
### Accessibility
|
|
228
|
+
- Semantic HTML: `<button>` not `<div onClick>`, `<nav>`, `<main>`, `<header>`
|
|
229
|
+
- Focus management for modals and drawers
|
|
230
|
+
- ARIA live regions for dynamic content: `aria-live="polite"`
|
|
231
|
+
- `htmlFor` on `<label>` linked to input `id`
|
|
232
|
+
- Keyboard navigation: all interactive elements reachable with Tab/Enter/Escape
|
|
233
|
+
|
|
234
|
+
### Props
|
|
235
|
+
- Destructure props at the top of the component
|
|
236
|
+
- Provide default values for optional props
|
|
237
|
+
- Avoid prop drilling past 2-3 levels — use Context or Zustand
|
|
238
|
+
- TypeScript interfaces for all prop shapes
|
|
239
|
+
|
|
240
|
+
### Events
|
|
241
|
+
- Pass handler references: `onClick={handleClick}` — not `onClick={handleClick()}`
|
|
242
|
+
- Avoid `.bind()` in render — creates new function every render
|
|
243
|
+
|
|
244
|
+
## Common Anti-Patterns
|
|
245
|
+
|
|
246
|
+
1. `key={index}` for dynamic lists — breaks reconciliation on reorder/delete
|
|
247
|
+
2. Missing cleanup in `useEffect` — memory leaks when component unmounts
|
|
248
|
+
3. `onClick={handleClick()}` — calls the function immediately instead of passing a reference
|
|
249
|
+
4. Storing derivable values in state — causes sync bugs and extra renders
|
|
250
|
+
5. Prop drilling past 3 levels — use Context or Zustand instead
|
|
251
|
+
6. Inline object/array in JSX props — breaks `React.memo` (`style={{ margin: 10 }}` → extract to constant)
|
|
252
|
+
7. No error boundary — a single thrown error crashes the entire component tree
|
|
253
|
+
8. Large context that updates frequently — split context by concern/update frequency
|
|
254
|
+
9. `useEffect` for data that could be fetched on the server — use TanStack Query or a framework
|
|
255
|
+
10. Mutating state directly — always return new references from state updates
|
|
256
|
+
|
|
257
|
+
## Performance Checklist
|
|
258
|
+
|
|
259
|
+
- [ ] `React.lazy` + `Suspense` on all route-level components
|
|
260
|
+
- [ ] `react-window` for lists with more than 100 items
|
|
261
|
+
- [ ] `useMemo`/`useCallback` only where React DevTools Profiler confirms a bottleneck
|
|
262
|
+
- [ ] React DevTools Profiler run against real data before optimizing
|
|
263
|
+
- [ ] Stable keys (`item.id`) on all dynamic lists
|
|
264
|
+
- [ ] Context split by update frequency — separate auth context from theme context
|
|
265
|
+
- [ ] `<img>` elements have explicit `width` and `height` to prevent layout shift
|
|
266
|
+
- [ ] Bundle size checked with `source-map-explorer` or Vite bundle visualizer
|
|
267
|
+
- [ ] No anonymous functions in frequently-rendered list items
|
|
268
|
+
- [ ] Error boundaries wrapping all major feature subtrees
|