Awesome-omni-skill react-fluent-ui-patterns
Skill for React TypeScript frontend development with Fluent UI Copilot components. Use when creating UI components, handling SSE streams, working with chat interfaces, or implementing theme support.
install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/frontend/react-fluent-ui-patterns" ~/.claude/skills/diegosouzapw-awesome-omni-skill-react-fluent-ui-patterns && rm -rf "$T"
manifest:
skills/frontend/react-fluent-ui-patterns/SKILL.mdsource content
React Fluent UI Development Skill
This skill provides patterns and guidance for developing the React TypeScript frontend in the Foundry Agent Accelerator.
Project Structure
src/frontend/ ├── src/ │ ├── main.tsx # App entry point │ ├── components/ │ │ ├── App.tsx # Root component │ │ ├── agents/ # Chat-related components │ │ │ ├── AgentPreview.tsx │ │ │ ├── chatbot/ # Chat input components │ │ │ └── hooks/ # Custom React hooks │ │ └── core/ # Shared/reusable components │ │ └── theme/ # Theme provider │ └── types/ │ └── chat.ts # TypeScript interfaces └── package.json
Component Documentation Format
Every component file MUST start with:
/** * ============================================================================= * COMPONENT NAME - Brief Description * ============================================================================= * * WHAT THIS FILE DOES: * -------------------- * 1. First responsibility * 2. Second responsibility * * HOW TO CUSTOMIZE: * ----------------- * - Customization instructions * * ============================================================================= */
Interface Naming Convention
Prefix all interface names with
I:
interface IAgent { id: string; name: string; description?: string | null; model: string; metadata?: Record<string, any>; } interface IMessage { id: string; content: string; role: 'user' | 'assistant'; }
Component Pattern
import { ReactNode, useState, useCallback } from "react"; import { Button, Body1 } from "@fluentui/react-components"; import styles from "./ComponentName.module.css"; interface IComponentNameProps { title: string; onAction?: () => void; } export function ComponentName({ title, onAction }: IComponentNameProps): ReactNode { // ------------------------------------------------------------------------- // STATE // ------------------------------------------------------------------------- const [isActive, setIsActive] = useState(false); // ------------------------------------------------------------------------- // HANDLERS // ------------------------------------------------------------------------- const handleClick = useCallback(() => { setIsActive(!isActive); onAction?.(); }, [isActive, onAction]); // ------------------------------------------------------------------------- // RENDER // ------------------------------------------------------------------------- return ( <div className={styles.container}> <Body1>{title}</Body1> <Button onClick={handleClick} appearance="primary"> Click Me </Button> </div> ); }
CSS Modules
File naming
- Component:
ComponentName.tsx - Styles:
ComponentName.module.css
CSS Module Pattern
/* ComponentName.module.css */ .container { display: flex; flex-direction: column; padding: 16px; gap: 8px; } .header { font-size: 1.5rem; font-weight: 600; } /* Use kebab-case for multi-word classes */ .action-button { margin-top: 8px; }
Usage
import styles from "./ComponentName.module.css"; <div className={styles.container}> <h1 className={styles.header}>Title</h1> <button className={styles.actionButton}>Action</button> </div>
Fluent UI Components
import { Body1, Button, Caption1, Title2, Spinner, Input, Textarea, } from "@fluentui/react-components"; import { ChatRegular, SendRegular, SettingsRegular, DismissRegular, } from "@fluentui/react-icons";
Fluent UI Copilot Components
For chat interfaces:
import { CopilotProvider } from "@fluentui-copilot/react-provider"; import { CopilotChat } from "@fluentui-copilot/react-copilot-chat";
SSE (Server-Sent Events) Pattern
Handle streaming responses from the backend:
const processStream = async (response: Response) => { const reader = response.body?.getReader(); const decoder = new TextDecoder(); if (!reader) return; let buffer = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.startsWith("data: ")) { const data = JSON.parse(line.slice(6)); switch (data.type) { case "message": appendToMessage(data.content); break; case "completed_message": setFinalMessage(data.content); break; case "stream_end": setIsLoading(false); break; } } } } };
Custom Hooks
Place in
hooks/ directory:
// hooks/useFormatTimestamp.ts import { useMemo } from "react"; export function useFormatTimestamp(timestamp: number): string { return useMemo(() => { const date = new Date(timestamp); return date.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", }); }, [timestamp]); }
Theme Support
Use the ThemeProvider:
import { ThemeProvider } from "./core/theme/ThemeProvider"; return ( <ThemeProvider> <div className="app-container"> <YourComponent /> </div> </ThemeProvider> );
File Attachment Handling
interface IFileAttachment { name: string; type: string; // MIME type data: string; // Base64-encoded } const handleFileSelect = async (file: File): Promise<IFileAttachment> => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const base64 = (reader.result as string).split(",")[1]; resolve({ name: file.name, type: file.type, data: base64 }); }; reader.onerror = reject; reader.readAsDataURL(file); }); };
Markdown Rendering
import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; export function MessageContent({ content }: { content: string }): ReactNode { return ( <ReactMarkdown remarkPlugins={[remarkGfm, remarkMath]} rehypePlugins={[rehypeKatex]} > {content} </ReactMarkdown> ); }
Component Location Guide
| Component Type | Location |
|---|---|
| Agent/Chat related | |
| Shared/Reusable | |
| Theme related | |
| Chat input | |
| Custom hooks | |