
Syncfusion React Inline Ai Assist
- 383 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
syncfusion-react-inline-ai-assist is a Claude Code skill that helps developers embed Syncfusion inline AI assistance controls into React applications with correct component setup and interaction patterns.
About
syncfusion-react-inline-ai-assist is a frontend integration skill from syncfusion/react-ui-components-skills for React developers adding AI-powered inline assistance to enterprise UIs. The skill covers Syncfusion component configuration for contextual AI suggestions, completions, or assist panels embedded directly in editors and forms. Developers reach for syncfusion-react-inline-ai-assist when a React app already uses Syncfusion and needs copilot-style inline help without building custom AI UI primitives. Catalog metadata is thin, so the skill primarily accelerates Syncfusion-specific inline AI assist APIs during active React build work.
- syncfusion-react-inline-ai-assist
Syncfusion React Inline Ai Assist by the numbers
- 383 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,097 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-inline-ai-assistAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 383 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
How do you add Syncfusion inline AI assist in React?
Use syncfusion-react-inline-ai-assist for development tasks
Who is it for?
React developers using Syncfusion who need embedded inline AI assistance in editors, forms, or dashboards.
Skip if: Projects without Syncfusion licenses or teams building fully custom copilot UIs outside Syncfusion component APIs.
When should I use this skill?
A React app needs Syncfusion inline AI assist wired into an editor, form, or dashboard surface.
What you get
A configured Syncfusion inline AI assist component integrated into a React application view.
- inline AI assist component integration
Files
Syncfusion React Syncfusion React Inline AI Assist Component
Component Overview
The Inline AI Assist component provides intelligent text processing capabilities for your React applications. It enables AI-powered suggestions, content generation, and interactive prompt-response workflows with support for multiple AI service integrations.
Key Capabilities
- Multi-AI Service Integration: Connect to OpenAI, Google Gemini, Lite-LLM, and Ollama for flexible AI backend options
- Real-Time Response Streaming: Enable
enableStreamingfor progressive response updates during content generation - Command & Response Actions: Configure predefined commands for quick AI tasks and custom response actions
- Inline Toolbar: Add custom toolbar items with icons, buttons, and separators for enhanced user interactions
- Inline & Popup Modes: Display AI responses inline with existing content or in a floating popup window
- Flexible Template Customization: Customize prompt input and response display using string, function, or JSX templates
- Internationalization (i18n) & RTL: Support for multiple languages and right-to-left text direction
- Event Handling: Lifecycle events including
created,promptRequest,open, andclosefor precise control - Public Methods: Programmatic access with
addResponse(),executePrompt(),showPopup(), and more - Prompt History: Track prompt-response conversations with persistent history management
- Accessibility & Theming: Compatible with Material, Bootstrap, Fluent, and Tailwind CSS themes
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation via npm
- CSS theme imports (Material, Bootstrap, Fluent, Tailwind)
- Component rendering
- Custom styling with
cssClassproperty - Running your first example
Template Customization
📄 Read: references/template-customization.md
editorTemplateproperty: Customize prompt input arearesponseTemplateproperty: Customize response display- String templates, function templates, JSX.Element templates
- Rich text editor integration
- Voice input integration
- Code syntax highlighting
- Markdown rendering
Internationalization (i18n) and RTL
📄 Read: references/internationalization.md
localeproperty: Set language and regional formattingenableRtlproperty: Enable right-to-left text direction- Available locale codes and setup
- Arabic, Hebrew, Persian support
- Multi-language applications
- Browser language detection
- Custom localization strings
Positioning and Targeting
📄 Read: references/positioning-and-targeting.md
relateToproperty: Position relative to DOM elementstargetproperty: Specify where to append the componentresponseModeproperty: Inline vs Popup display modes- Practical positioning scenarios
Command Settings
📄 Read: references/command-settings.md
- Configure command items for quick actions
- Command properties: id, label, iconCss, disabled, prompt, tooltip
- Group commands with
groupByproperty - Handle
itemSelectevents - Set popup dimensions
Response Settings
📄 Read: references/response-settings.md
- Built-in response items (accept, reject)
- Adding custom response actions
- Response item properties and configuration
- Group response items with
groupBy - Handle response
itemSelectevents
Inline Toolbar Customization
📄 Read: references/inline-toolbar.md
- Configure toolbar items (buttons, separators, inputs)
- Built-in items and custom items
- Item properties: text, iconCss, type, visible, disabled, align
- Tab key navigation with
tabIndex - Custom item templates
- Toolbar positioning: Inline vs Bottom
itemClickevent handling with complete event args
Events
📄 Read: references/events.md
createdevent: Component render completepromptRequestevent: Prompt submitted by useropenevent: Popup openedcloseevent: Popup closed- Event handler patterns and examples
Methods
📄 Read: references/methods.md
addResponse(response): Add AI response to componentexecutePrompt(prompt): Execute prompt dynamicallyshowPopup(coordinates): Open the popuphidePopup(): Close the popupshowCommandPopup(): Show command actionshideCommandPopup(): Hide command actions
AI Service Integrations
📄 Read: references/ai-integrations.md
enableStreamingproperty: Real-time response streaming- OpenAI API integration with streaming
- Google Gemini AI integration with streaming
- Lite-LLM service integration
- Ollama local LLM integration with streaming
- API credential setup
- Prompt handling and response streaming
- Performance optimization and error handling
Quick Start
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
function App() {
const assistRef = React.useRef(null);
const handlePromptRequest = () => {
// Simulate AI response
setTimeout(() => {
const response = 'Your AI-generated response here';
assistRef.current?.addResponse(response);
}, 1000);
};
const handleShowPopup = () => {
assistRef.current?.showPopup();
};
return (
<div>
<button onClick={handleShowPopup} className="e-btn e-primary">
Ask AI
</button>
<InlineAIAssistComponent
id="inlineAssist"
ref={assistRef}
relateTo="button"
promptRequest={handlePromptRequest}
popupWidth="500px"
/>
</div>
);
}
export default App;Common Patterns
Pattern 1: AI-Assisted Text Editing
Combine the component with a contentEditable div to enable AI-powered suggestions while editing:
const handleResponseItemSelect = (args) => {
if (args.command.label === 'Accept') {
const lastResponse = assistRef.current.prompts?.[assistRef.current.prompts.length - 1]?.response;
if (lastResponse && editableRef.current) {
editableRef.current.innerHTML = lastResponse;
}
}
};
<InlineAIAssistComponent
responseSettings={{
itemSelect: handleResponseItemSelect
}}
/>Pattern 2: Command-Based Actions
Set up predefined commands for common AI tasks:
const commandSettings = {
commands: [
{ id: 'summarize', label: 'Summarize', iconCss: 'e-icons e-compress', prompt: 'Summarize this text' },
{ id: 'expand', label: 'Expand', iconCss: 'e-icons e-expand', prompt: 'Expand this text' },
{ id: 'fix', label: 'Fix Grammar', iconCss: 'e-icons e-check-box', prompt: 'Fix grammar and spelling' }
]
};
<InlineAIAssistComponent commandSettings={commandSettings} />Pattern 3: Custom Toolbar Actions
Add custom toolbar items to trigger component methods:
const handleToolbarItemClick = (args) => {
if (args.item.id === 'customAction') {
assistRef.current?.executePrompt('User-defined prompt');
}
};
const inlineToolbarSettings = {
items: [
{ id: 'customAction', text: 'Custom', iconCss: 'e-icons e-settings' }
],
itemClick: handleToolbarItemClick
};Pattern 4: Response Display Modes
Switch between inline editing and popup responses:
// Inline mode: Response appears inline
<InlineAIAssistComponent responseMode="Inline" />
// Popup mode: Response in floating popup
<InlineAIAssistComponent responseMode="Popup" popupWidth="400px" />Pattern 5: Lifecycle Management
Use events to coordinate component state:
const handleCreated = () => {
console.log('Component initialized');
};
const handlePromptRequest = (args) => {
console.log('Prompt submitted:', args.prompt);
};
<InlineAIAssistComponent
created={handleCreated}
promptRequest={handlePromptRequest}
open={() => console.log('Popup opened')}
close={() => console.log('Popup closed')}
/>Key Configuration Properties
| Property | Type | Default | Purpose |
|---|---|---|---|
editorTemplate | string \ | function \ | JSX.Element |
responseTemplate | string \ | function \ | JSX.Element |
enableStreaming | boolean | false | Enable real-time response streaming |
locale | string | 'en-US' | Language and regional formatting |
enableRtl | boolean | false | Enable right-to-left text direction |
enablePersistence | boolean | false | Persist component state across reloads |
cssClass | string | '' | Custom CSS classes for styling |
relateTo | string \ | HTMLElement | - |
target | string \ | HTMLElement | 'body' |
responseMode | string | 'Popup' | 'Inline' or 'Popup' |
popupWidth | string \ | number | '400px' |
popupHeight | string \ | number | 'auto' |
zIndex | number | 1000 | Popup z-index |
placeholder | string | 'Ask or generate AI content..' | Prompt textarea placeholder |
prompt | string | '' | Default prompt text |
prompts | array | [] | Prompt-response collection |
commandSettings | CommandSettingsModel | null | Command configuration |
responseSettings | ResponseSettingsModel | null | Response action configuration |
inlineToolbarSettings | InlineToolbarSettingsModel | null | Toolbar customization |
For complete examples and advanced scenarios, explore individual reference files above.
AI Service Integrations
Table of Contents
- Overview
- Streaming Responses (enableStreaming)
- OpenAI Integration
- Google Gemini Integration
- Lite-LLM Integration
- Ollama Local LLM Integration
- Integration Patterns
- Complete Examples
Overview
The Inline AI Assist component is designed to work with various AI services. You handle the AI service integration yourself by:
1. Listening to `promptRequest` event - User submits a prompt 2. Calling your AI service - Send prompt to OpenAI, Gemini, or other service 3. Adding response - Use addResponse() method to display result
This gives you complete flexibility to use any AI service you prefer.
Streaming Responses (enableStreaming)
The enableStreaming property enables real-time streaming of AI responses, providing a better user experience by displaying content as it's generated rather than waiting for the complete response.
Property Details
Type: boolean Default: false Component Property: enableStreaming
When to Use Streaming
✅ Enable streaming when:
- Working with LLMs that support streaming (OpenAI, Gemini, etc.)
- Responses are typically long (> 100 words)
- User experience is priority (immediate feedback)
- Building chat-like interfaces
❌ Don't enable streaming when:
- AI service doesn't support streaming
- Responses are short and fast (< 1 second)
- You need complete response for post-processing
- Bandwidth is limited
Basic Usage
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
return (
<InlineAIAssistComponent
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
);
};
export default App;How Streaming Works
When enableStreaming is enabled:
1. Component Behavior Changes:
- Response area updates incrementally as text arrives
- No need to wait for complete response
- Better perceived performance
2. Your Implementation:
- Call
addResponse()multiple times with cumulative text - Each call updates the displayed response
- Component handles the UI updates automatically
3. User Experience:
- Text appears character-by-character or word-by-word
- Immediate feedback that processing started
- Natural chat-like interaction
Streaming with OpenAI
import { InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import OpenAI from 'openai';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const openai = new OpenAI({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
dangerouslyAllowBrowser: true
});
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
let fullResponse = '';
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true // Enable streaming
});
// Process each chunk as it arrives
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
fullResponse += content;
// Update response incrementally
assistRef.current?.addResponse(fullResponse);
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Streaming with Google Gemini
import { InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import { GoogleGenerativeAI } from '@google/generative-ai';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const genAI = new GoogleGenerativeAI(process.env.REACT_APP_GEMINI_API_KEY!);
const model = genAI.getGenerativeModel({ model: 'gemini-pro' });
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
let fullResponse = '';
// Generate content with streaming
const result = await model.generateContentStream(args.prompt);
// Process each chunk
for await (const chunk of result.stream) {
const chunkText = chunk.text();
fullResponse += chunkText;
// Update response incrementally
assistRef.current?.addResponse(fullResponse);
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Streaming with Ollama
import { InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const OLLAMA_API_URL = 'http://localhost:11434/api/generate';
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const response = await fetch(OLLAMA_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama2',
prompt: args.prompt,
stream: true // Enable streaming
})
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let fullResponse = '';
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
// Parse JSON chunk
try {
const json = JSON.parse(chunk);
fullResponse += json.response;
// Update response incrementally
assistRef.current?.addResponse(fullResponse);
} catch (e) {
// Skip malformed JSON chunks
console.warn('Skipping chunk:', chunk);
}
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Advanced Streaming with Progress Indicator
Show visual feedback during streaming:
const StreamingAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [isStreaming, setIsStreaming] = React.useState(false);
const [streamProgress, setStreamProgress] = React.useState(0);
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
setIsStreaming(true);
setStreamProgress(0);
try {
let fullResponse = '';
let chunkCount = 0;
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
fullResponse += content;
chunkCount++;
// Update progress
setStreamProgress(chunkCount);
// Update response
assistRef.current?.addResponse(fullResponse);
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
} finally {
setIsStreaming(false);
}
};
return (
<div>
{isStreaming && (
<div className="streaming-indicator">
<span className="spinner"></span>
Streaming... ({streamProgress} chunks received)
</div>
)}
<InlineAIAssistComponent
ref={assistRef}
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
</div>
);
};Streaming with Error Recovery
Implement robust error handling for streaming:
const RobustStreamingAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [retryCount, setRetryCount] = React.useState(0);
const MAX_RETRIES = 3;
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
let attempt = 0;
while (attempt < MAX_RETRIES) {
try {
let fullResponse = '';
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true,
stream_options: { include_usage: true }
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
fullResponse += content;
assistRef.current?.addResponse(fullResponse);
}
// Success - break retry loop
setRetryCount(0);
break;
} catch (error) {
attempt++;
setRetryCount(attempt);
if (attempt >= MAX_RETRIES) {
assistRef.current?.addResponse(
`Failed after ${MAX_RETRIES} attempts. Error: ${error.message}`
);
break;
}
// Wait before retrying (exponential backoff)
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
enableStreaming={true}
promptRequest={handlePromptRequest}
/>
);
};Performance Considerations
Throttling Updates
For very fast streams, throttle UI updates to improve performance:
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
let fullResponse = '';
let lastUpdateTime = Date.now();
const UPDATE_INTERVAL_MS = 50; // Update every 50ms
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
fullResponse += content;
// Throttle updates
const now = Date.now();
if (now - lastUpdateTime >= UPDATE_INTERVAL_MS) {
assistRef.current?.addResponse(fullResponse);
lastUpdateTime = now;
}
}
// Final update to ensure complete response
assistRef.current?.addResponse(fullResponse);
};Buffer Chunks
Buffer small chunks to reduce update frequency:
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
let fullResponse = '';
let buffer = '';
const BUFFER_SIZE = 10; // Words
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
buffer += content;
// Update when buffer reaches threshold
if (buffer.split(' ').length >= BUFFER_SIZE) {
fullResponse += buffer;
assistRef.current?.addResponse(fullResponse);
buffer = '';
}
}
// Flush remaining buffer
if (buffer) {
fullResponse += buffer;
assistRef.current?.addResponse(fullResponse);
}
};Streaming Best Practices
1. Always Handle Errors:
- Wrap streaming logic in try-catch
- Provide meaningful error messages
- Implement retry logic for transient failures
2. Performance:
- Throttle UI updates for very fast streams
- Buffer small chunks to reduce render frequency
- Consider debouncing for large responses
3. User Experience:
- Show streaming indicator/spinner
- Allow users to cancel streaming
- Display progress information
4. Testing:
- Test with slow network conditions
- Test error scenarios (network failure, API errors)
- Verify complete response accuracy
5. Resource Management:
- Clean up streams on component unmount
- Cancel ongoing requests when new prompt submitted
- Monitor memory usage with long responses
6. Security:
- Validate and sanitize streamed content
- Implement rate limiting
- Monitor for malicious content
Comparison: Streaming vs Non-Streaming
| Aspect | Streaming (enableStreaming: true) | Non-Streaming (enableStreaming: false) |
|---|---|---|
| User Experience | Immediate feedback, word-by-word | Wait for complete response |
| Perceived Speed | Feels faster, progressive | May feel slower, all-at-once |
| Implementation | Call addResponse() multiple times | Call addResponse() once |
| Error Handling | Must handle partial responses | Simpler error handling |
| Performance | More UI updates | Single UI update |
| Best For | Long responses, chat interfaces | Short responses, fast APIs |
| Network Usage | Continuous connection | Single request-response |
Migration from Non-Streaming to Streaming
If you have existing non-streaming code:
Before (Non-Streaming):
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
const response = await callAI(args.prompt);
assistRef.current?.addResponse(response);
};After (Streaming):
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
let fullResponse = '';
const stream = await callAIStreaming(args.prompt);
for await (const chunk of stream) {
fullResponse += chunk;
assistRef.current?.addResponse(fullResponse); // Called multiple times
}
};
// Enable streaming in component
<InlineAIAssistComponent enableStreaming={true} {...props} />OpenAI Integration
Setup: Get API Key
1. Sign up at openai.com 2. Create API key in API keys page 3. Store securely (use environment variables, not hardcoded)
Install OpenAI Package
npm install openaiBasic Implementation
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import OpenAI from 'openai';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const openai = new OpenAI({
apiKey: process.env.REACT_APP_OPENAI_API_KEY,
dangerouslyAllowBrowser: true // Only for development!
});
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const message = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{ role: 'user', content: args.prompt }
]
});
const response = message.choices[0].message.content || '';
assistRef.current?.addResponse(response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Advanced: Streaming Responses
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
let fullResponse = '';
const stream = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
fullResponse += content;
// Update response incrementally
assistRef.current?.addResponse(fullResponse);
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};With Context History
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [conversationHistory, setConversationHistory] = React.useState<any[]>([]);
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
// Build message history
const messages = [
...conversationHistory,
{ role: 'user', content: args.prompt }
];
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages
});
const assistantMessage = response.choices[0].message.content || '';
// Add to history
setConversationHistory([
...messages,
{ role: 'assistant', content: assistantMessage }
]);
assistRef.current?.addResponse(assistantMessage);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};Google Gemini Integration
Setup: Get API Key
1. Visit Google AI Studio 2. Click "Create API Key" 3. Store securely in environment variables
Install Gemini Package
npm install @google/generative-aiBasic Implementation
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { GoogleGenerativeAI } from '@google/generative-ai';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const genAI = new GoogleGenerativeAI(process.env.REACT_APP_GEMINI_API_KEY!);
const model = genAI.getGenerativeModel({ model: 'gemini-pro' });
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const result = await model.generateContent(args.prompt);
const response = result.response.text();
assistRef.current?.addResponse(response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;With Safety Settings
const model = genAI.getGenerativeModel({
model: 'gemini-pro',
safetySettings: [
{
category: HarmCategory.HARM_CATEGORY_HARASSMENT,
threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH,
}
]
});
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const result = await model.generateContent({
contents: [{
role: 'user',
parts: [{ text: args.prompt }]
}]
});
const response = result.response.text();
assistRef.current?.addResponse(response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};With Vision (Image Analysis)
const model = genAI.getGenerativeModel({ model: 'gemini-pro-vision' });
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
// If image available
const imagePart = {
inlineData: {
data: imageBase64,
mimeType: 'image/jpeg'
}
};
const result = await model.generateContent([
args.prompt,
imagePart
]);
const response = result.response.text();
assistRef.current?.addResponse(response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};Lite-LLM Integration
Setup
Lite-LLM is a library that provides a unified interface to multiple LLM providers.
npm install litellmBasic Implementation
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { LiteLLM } from 'litellm';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const llm = new LiteLLM({
apiKey: process.env.REACT_APP_LITELLM_API_KEY
});
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const response = await llm.completion({
model: 'gpt-3.5-turbo',
messages: [
{ role: 'user', content: args.prompt }
]
});
assistRef.current?.addResponse(response.choices[0].message.content);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Multiple Provider Support
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
const providers = ['openai', 'azure', 'anthropic'];
for (const provider of providers) {
try {
const response = await llm.completion({
model: `${provider}/gpt-3.5-turbo`,
messages: [{ role: 'user', content: args.prompt }]
});
assistRef.current?.addResponse(response.choices[0].message.content);
break; // Success, exit loop
} catch (error) {
console.error(`${provider} failed, trying next...`);
continue;
}
}
};Ollama Local LLM Integration
Setup
Ollama runs LLMs locally on your machine. Download from ollama.ai
# Install Ollama, then pull a model
ollama pull llama2
ollama serve # Start Ollama server (default: http://localhost:11434)Basic Implementation
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const OLLAMA_API_URL = 'http://localhost:11434/api/generate';
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const response = await fetch(OLLAMA_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama2',
prompt: args.prompt,
stream: false
})
});
const data = await response.json();
assistRef.current?.addResponse(data.response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Streaming Response
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const response = await fetch(OLLAMA_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'llama2',
prompt: args.prompt,
stream: true
})
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let fullResponse = '';
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const json = JSON.parse(chunk);
fullResponse += json.response;
// Update incrementally
assistRef.current?.addResponse(fullResponse);
}
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};Integration Patterns
Pattern 1: Error Handling with Fallback
const callAIService = async (prompt: string): Promise<string> => {
try {
// Try primary service
return await openai.chat.completions.create({ ... });
} catch (error) {
console.error('OpenAI failed, trying Gemini...');
try {
// Try fallback service
return await gemini.generateContent(prompt);
} catch (fallbackError) {
throw new Error('All AI services failed');
}
}
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
callAIService(args.prompt)
.then(response => assistRef.current?.addResponse(response))
.catch(error => assistRef.current?.addResponse(`Error: ${error.message}`));
};Pattern 2: Loading State Management
const App: React.FC = () => {
const [isLoading, setIsLoading] = React.useState(false);
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
setIsLoading(true);
try {
const response = await callAI(args.prompt);
assistRef.current?.addResponse(response);
} finally {
setIsLoading(false);
}
};
return (
<div>
{isLoading && <p>Processing...</p>}
<InlineAIAssistComponent promptRequest={handlePromptRequest} />
</div>
);
};Pattern 3: Token Limit Management
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
const maxTokens = 1000;
const estimatedTokens = args.prompt.split(' ').length * 1.3;
if (estimatedTokens > maxTokens) {
assistRef.current?.addResponse(
'Prompt too long. Please reduce and try again.'
);
return;
}
const response = await callAI(args.prompt);
assistRef.current?.addResponse(response);
};Complete Examples
Example 1: Multi-Service Provider
const MultiServiceAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [service, setService] = React.useState<'openai' | 'gemini' | 'ollama'>('openai');
const callService = async (prompt: string) => {
switch (service) {
case 'openai':
return await openai.chat.completions.create({ ... });
case 'gemini':
return await gemini.generateContent(prompt);
case 'ollama':
return await fetch('http://localhost:11434/api/generate', { ... });
default:
throw new Error('Unknown service');
}
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
callService(args.prompt)
.then(response => assistRef.current?.addResponse(response))
.catch(error => assistRef.current?.addResponse(`Error: ${error.message}`));
};
return (
<div>
<select value={service} onChange={(e) => setService(e.target.value as any)}>
<option>openai</option>
<option>gemini</option>
<option>ollama</option>
</select>
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
</div>
);
};Example 2: Backend API Integration
const BackendIntegration: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
const response = await fetch('/api/ai/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: args.prompt })
});
const data = await response.json();
assistRef.current?.addResponse(data.response);
} catch (error) {
assistRef.current?.addResponse(`Error: ${error.message}`);
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};Example 3: Context-Aware Responses
const ContextAwareAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [context, setContext] = React.useState<string>('');
const handlePromptRequest = async (args: InlinePromptRequestEventArgs) => {
const enrichedPrompt = `
Context: ${context}
User Request: ${args.prompt}
`;
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: enrichedPrompt }]
});
assistRef.current?.addResponse(response.choices[0].message.content || '');
};
return (
<div>
<textarea
placeholder="Provide context..."
onChange={(e) => setContext(e.target.value)}
/>
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
</div>
);
};Best Practices
1. Security: Never hardcode API keys; use environment variables 2. Error Handling: Always catch and display user-friendly errors 3. Rate Limiting: Implement rate limiting to avoid API quota exhaustion 4. Caching: Cache responses for identical prompts 5. Timeouts: Set reasonable timeouts for API calls 6. Monitoring: Log all API calls for debugging 7. Cost Management: Track token usage and costs 8. User Feedback: Show loading states during processing 9. Retry Logic: Implement exponential backoff for failed requests 10. Privacy: Don't send sensitive data to external services
Command Settings
Table of Contents
- Overview
- Command Item Properties
- Configuring Commands
- Grouping Commands
- Handling Command Selection
- Popup Dimensions
- Complete Examples
Overview
Commands provide quick-access actions for users to trigger predefined AI prompts. When a user clicks the command icon in the inline assistant, a popup menu displays all configured commands. Selecting a command executes the associated prompt automatically.
Commands are configured through the commandSettings property using the CommandSettingsModel interface.
Command Item Properties
Each command item in the commands array supports these properties:
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier for the command |
label | string | Yes | Display text shown in command popup |
prompt | string | Yes | AI prompt to execute when selected |
iconCss | string | No | CSS class for icon display |
disabled | boolean | No | Disable command (default: false) |
tooltip | string | No | Tooltip text on hover |
groupBy | string | No | Group name for command organization |
Configuring Commands
Basic Command Configuration
import { InlineAIAssistComponent, CommandSettingsModel } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'summarize',
label: 'Summarize',
prompt: 'Please summarize this text in 2-3 sentences'
},
{
id: 'expand',
label: 'Expand',
prompt: 'Please expand this text with more details and examples'
},
{
id: 'simplify',
label: 'Simplify',
prompt: 'Rewrite this text in simpler, easier-to-understand language'
}
]
};
return (
<InlineAIAssistComponent commandSettings={commandSettings} />
);
};
export default App;Adding Icons to Commands
Use Syncfusion icon CSS classes for consistency:
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'summarize',
label: 'Summarize',
iconCss: 'e-icons e-compress',
prompt: 'Summarize this text concisely'
},
{
id: 'translate',
label: 'Translate to Spanish',
iconCss: 'e-icons e-globe',
prompt: 'Translate this text to Spanish'
},
{
id: 'tone-formal',
label: 'Formal Tone',
iconCss: 'e-icons e-style',
prompt: 'Rewrite this text in a formal, professional tone'
},
{
id: 'tone-casual',
label: 'Casual Tone',
iconCss: 'e-icons e-chat',
prompt: 'Rewrite this text in a casual, conversational tone'
}
]
};Disabling Commands Conditionally
const App: React.FC = () => {
const [hasSelectedText, setHasSelectedText] = React.useState(false);
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'summarize',
label: 'Summarize',
prompt: 'Summarize: ',
disabled: !hasSelectedText
},
{
id: 'expand',
label: 'Expand',
prompt: 'Expand: ',
disabled: !hasSelectedText
}
]
};
const handleTextSelect = () => {
setHasSelectedText(true);
};
return (
<div>
<textarea onSelect={handleTextSelect} />
<InlineAIAssistComponent commandSettings={commandSettings} />
</div>
);
};Grouping Commands
Use the groupBy property to organize commands into logical groups. The popup displays group headers automatically.
const commandSettings: CommandSettingsModel = {
commands: [
// Content Generation group
{
id: 'generate-title',
label: 'Generate Title',
groupBy: 'Generate',
prompt: 'Generate a catchy title for this content'
},
{
id: 'generate-summary',
label: 'Generate Summary',
groupBy: 'Generate',
prompt: 'Generate a summary for this content'
},
// Content Refinement group
{
id: 'fix-grammar',
label: 'Fix Grammar',
groupBy: 'Refinement',
prompt: 'Fix all grammar and spelling errors'
},
{
id: 'improve-clarity',
label: 'Improve Clarity',
groupBy: 'Refinement',
prompt: 'Improve the clarity and readability of this text'
},
// Transformation group
{
id: 'to-bullet-points',
label: 'Convert to Bullet Points',
groupBy: 'Transform',
prompt: 'Convert this text to a bulleted list'
},
{
id: 'to-paragraph',
label: 'Convert to Paragraph',
groupBy: 'Transform',
prompt: 'Convert this list to paragraph format'
}
]
};Handling Command Selection
Detect when a command is selected using the itemSelect event:
Basic Event Handler
import { CommandItemSelectEventArgs } from '@syncfusion/ej2-react-interactive-chat';
const handleCommandSelect = (args: CommandItemSelectEventArgs) => {
console.log('Selected command ID:', args.command.id);
console.log('Command label:', args.command.label);
console.log('Prompt:', args.command.prompt);
};
const commandSettings: CommandSettingsModel = {
commands: [
{ id: 'cmd1', label: 'Command 1', prompt: 'Prompt 1' }
],
itemSelect: handleCommandSelect
};
<InlineAIAssistComponent commandSettings={commandSettings} />Advanced Event Handler with Logging
const handleCommandSelect = (args: CommandItemSelectEventArgs) => {
const timestamp = new Date().toLocaleTimeString();
console.log(`[${timestamp}] Command executed: ${args.command.label}`);
// Log to analytics
trackAnalytics('command_selected', {
commandId: args.command.id,
label: args.command.label
});
// Show notification
showNotification(`Executing: ${args.command.label}`);
};Conditional Logic Based on Selected Command
const handleCommandSelect = (args: CommandItemSelectEventArgs) => {
switch (args.command.id) {
case 'summarize':
console.log('User requested summary');
break;
case 'expand':
console.log('User requested expansion');
break;
case 'fix-grammar':
console.log('User requested grammar check');
break;
default:
console.log('Unknown command');
}
};Popup Dimensions
Control the command popup size using popupWidth and popupHeight:
const commandSettings: CommandSettingsModel = {
popupWidth: '300px', // CSS value or number (px)
popupHeight: '400px', // CSS value or number (px)
commands: [
{ id: 'cmd1', label: 'Command 1', prompt: 'Prompt 1' }
]
};
<InlineAIAssistComponent commandSettings={commandSettings} />Responsive Dimensions
const getCommandPopupWidth = () => {
return window.innerWidth < 600 ? '250px' : '350px';
};
const commandSettings: CommandSettingsModel = {
popupWidth: getCommandPopupWidth(),
commands: [...]
};Complete Examples
Example 1: Content Editor with Writing Commands
const ContentEditor: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'enhance-writing',
label: 'Enhance Writing',
iconCss: 'e-icons e-edit',
prompt: 'Improve the writing quality, clarity, and engagement'
},
{
id: 'check-tone',
label: 'Check Tone',
iconCss: 'e-icons e-comment',
prompt: 'Analyze the tone and suggest improvements for professionalism'
},
{
id: 'plagiarism-check',
label: 'Check Plagiarism',
iconCss: 'e-icons e-search',
prompt: 'Check for plagiarism and suggest unique alternatives'
}
],
popupWidth: '280px',
itemSelect: (args) => {
console.log('Writing command selected:', args.command.label);
}
};
return (
<div className="editor">
<textarea id="content-area" placeholder="Write your content..." />
<InlineAIAssistComponent
ref={assistRef}
commandSettings={commandSettings}
/>
</div>
);
};Example 2: Code Assistant with Development Commands
const CodeAssistant: React.FC = () => {
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'explain',
label: 'Explain Code',
iconCss: 'e-icons e-help',
prompt: 'Explain what this code does in simple terms',
groupBy: 'Understanding'
},
{
id: 'optimize',
label: 'Optimize',
iconCss: 'e-icons e-speed',
prompt: 'Optimize this code for better performance',
groupBy: 'Optimization'
},
{
id: 'add-comments',
label: 'Add Comments',
iconCss: 'e-icons e-note',
prompt: 'Add helpful comments to explain the code',
groupBy: 'Documentation'
},
{
id: 'find-bugs',
label: 'Find Bugs',
iconCss: 'e-icons e-bug',
prompt: 'Identify potential bugs and issues in this code',
groupBy: 'Quality'
}
],
popupWidth: '320px',
popupHeight: '350px'
};
return (
<pre id="code-editor">
{`function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
total = total + items[i].price;
}
return total;
}`}
<InlineAIAssistComponent commandSettings={commandSettings} />
</pre>
);
};Example 3: E-Commerce with Product Commands
const ProductManager: React.FC = () => {
const commandSettings: CommandSettingsModel = {
commands: [
{
id: 'improve-description',
label: 'Improve Description',
prompt: 'Make this product description more compelling and SEO-friendly',
groupBy: 'SEO'
},
{
id: 'generate-keywords',
label: 'Generate Keywords',
prompt: 'Generate relevant keywords for this product',
groupBy: 'SEO'
},
{
id: 'create-catchy-title',
label: 'Create Title',
prompt: 'Create a catchy, keyword-rich product title',
groupBy: 'Content'
},
{
id: 'write-benefits',
label: 'Write Benefits',
prompt: 'Write compelling customer benefits for this product',
groupBy: 'Content'
}
],
itemSelect: (args) => {
console.log('Product optimization command:', args.command.id);
}
};
return (
<div className="product-editor">
<textarea placeholder="Product description..." />
<InlineAIAssistComponent commandSettings={commandSettings} />
</div>
);
};Best Practices
1. Descriptive Labels: Use clear, action-oriented labels ("Fix Grammar" vs "Grammar") 2. Logical Grouping: Organize related commands by category (Content, Optimization, Quality) 3. Consistent Icons: Use Syncfusion icon set for visual consistency 4. Context-Aware: Enable/disable commands based on selected content 5. Detailed Prompts: Include specific instructions in the prompt string 6. Popup Sizing: Set dimensions based on typical command count (5-15 commands fits 250px width) 7. Error Handling: Track command selections for analytics and debugging
Events
Table of Contents
- Overview
- created Event
- promptRequest Event
- open Event
- close Event
- Event Handler Patterns
- Complete Examples
Overview
The Inline AI Assist component provides several lifecycle and interaction events that you can hook into to implement custom logic. These events are triggered at different points in the component's lifecycle and user interactions.
created Event
Triggered when the component finishes rendering and initialization.
When It Fires
After all DOM elements are created, CSS applied, and component is ready for interaction.
Event Signature
type CreatedEventHandler = () => void;Basic Usage
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const handleCreated = () => {
console.log('Inline AI Assist component is ready');
// Initialize third-party libraries
// Set up analytics tracking
// Fetch initial data
};
return (
<InlineAIAssistComponent created={handleCreated} />
);
};
export default App;Use Cases
1. Initialize analytics: Track component load 2. Set up listeners: Attach to parent elements 3. Load saved state: Restore user preferences 4. Validate setup: Confirm AI service connection
Example: Initialize with Data
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handleCreated = () => {
// Load user's saved prompts
loadSavedPrompts().then(prompts => {
console.log('Prompts loaded:', prompts.length);
});
// Initialize AI service
initializeAIService();
// Set focus to input
const inputElement = document.querySelector('.e-aiassist-input');
if (inputElement) {
(inputElement as HTMLElement).focus();
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
created={handleCreated}
/>
);
};promptRequest Event
Triggered when the user submits a prompt (clicks send or presses Enter).
When It Fires
After user enters text and triggers send action (built-in send button or Enter key).
Event Arguments
interface InlinePromptRequestEventArgs {
prompt: string; // The user's prompt text
cancel: boolean; // Set to true to cancel the request
}Basic Usage
import { InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
console.log('User prompt:', args.prompt);
// Simulate AI processing
setTimeout(() => {
const response = 'AI-generated response';
assistRef.current?.addResponse(response);
}, 1000);
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Use Cases
1. Send to AI service: Forward prompt to OpenAI, Gemini, etc. 2. Validate prompt: Check for content policies 3. Add context: Augment prompt with additional data 4. Track analytics: Log user queries 5. Cancel request: Block certain prompts
Example: Validation and Context
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
// Validate prompt content
if (args.prompt.length < 5) {
args.cancel = true;
showNotification('Prompt must be at least 5 characters');
return;
}
// Add context to prompt
const context = 'Context information...';
const enrichedPrompt = `${context}\n\nUser request: ${args.prompt}`;
// Send to AI service
callAIService(enrichedPrompt).then(response => {
assistRef.current?.addResponse(response);
});
};Example: Implement Prompt History
const App: React.FC = () => {
const [promptHistory, setPromptHistory] = React.useState<string[]>([]);
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
// Add to history
setPromptHistory(prev => [args.prompt, ...prev]);
// Save to database
savePromptToDatabase(args.prompt);
// Process with AI
processWithAI(args.prompt).then(response => {
assistRef.current?.addResponse(response);
});
};
return (
<div>
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
<div>
<h3>History</h3>
{promptHistory.map((p, i) => (
<p key={i}>{p}</p>
))}
</div>
</div>
);
};open Event
Triggered when the component popup opens.
When It Fires
When the popup is opened (via user interaction, programmatic call, or component initialization).
Event Arguments
import { OpenEventArgs } from '@syncfusion/ej2-popups';
interface OpenEventArgs {
name: 'open';
element: HTMLElement; // The popup element
}Basic Usage
import { InlineAIAssistComponent, OpenEventArgs } from '@syncfusion/ej2-popups';
import React from 'react';
const App: React.FC = () => {
const handlePopupOpen = (args: OpenEventArgs) => {
console.log('Popup opened');
// Focus input when popup opens
const input = args.element?.querySelector('textarea');
if (input) {
(input as HTMLElement).focus();
}
};
return (
<InlineAIAssistComponent open={handlePopupOpen} />
);
};
export default App;Use Cases
1. Focus input: Set focus to prompt field 2. Track analytics: Log popup open events 3. Initialize data: Load suggestions when popup opens 4. Adjust layout: Reposition if needed
Example: Load Suggestions on Open
const handlePopupOpen = async (args: OpenEventArgs) => {
// Load recent prompts
const suggestions = await loadSuggestions();
console.log('Suggestions loaded:', suggestions);
// Track analytics
trackEvent('assist_popup_opened');
// Announce for accessibility
announceToScreenReader('AI Assist popup opened');
};close Event
Triggered when the component popup closes.
When It Fires
When the popup is closed (user clicks outside, presses Escape, or programmatic call).
Event Arguments
import { CloseEventArgs } from '@syncfusion/ej2-popups';
interface CloseEventArgs {
name: 'close';
element: HTMLElement; // The popup element
}Basic Usage
import { InlineAIAssistComponent, CloseEventArgs } from '@syncfusion/ej2-popups';
import React from 'react';
const App: React.FC = () => {
const handlePopupClose = (args: CloseEventArgs) => {
console.log('Popup closed');
// Clean up any pending operations
};
return (
<InlineAIAssistComponent close={handlePopupClose} />
);
};
export default App;Use Cases
1. Cleanup: Clear temporary data 2. Analytics: Track popup close events 3. Save state: Persist any unsaved changes 4. Reset UI: Clear highlights or selections
Event Handler Patterns
Pattern 1: Multiple Event Handlers
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handleCreated = () => {
console.log('Component ready');
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
console.log('Prompt submitted:', args.prompt);
};
const handlePopupOpen = (args: OpenEventArgs) => {
console.log('Popup opened');
};
const handlePopupClose = (args: CloseEventArgs) => {
console.log('Popup closed');
};
return (
<InlineAIAssistComponent
ref={assistRef}
created={handleCreated}
promptRequest={handlePromptRequest}
open={handlePopupOpen}
close={handlePopupClose}
/>
);
};Pattern 2: Event Aggregation
const handleComponentEvent = (eventType: string, eventData?: any) => {
const timestamp = new Date().toLocaleTimeString();
console.log(`[${timestamp}] Event: ${eventType}`, eventData);
// Send to analytics
trackEvent(eventType, eventData);
};
const inlineAiAssistProps = {
created: () => handleComponentEvent('created'),
promptRequest: (args: InlinePromptRequestEventArgs) =>
handleComponentEvent('promptRequest', { prompt: args.prompt }),
open: () => handleComponentEvent('open'),
close: () => handleComponentEvent('close')
};
<InlineAIAssistComponent {...inlineAiAssistProps} />Pattern 3: Conditional Logic
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
// Cancel if user not authenticated
if (!isAuthenticated()) {
args.cancel = true;
showLoginDialog();
return;
}
// Process normally
processPrompt(args.prompt);
};Complete Examples
Example 1: Content Generation Workflow
const ContentGenerator: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [isProcessing, setIsProcessing] = React.useState(false);
const handleCreated = () => {
console.log('Content Generator initialized');
initializeTheme();
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
setIsProcessing(true);
// Send prompt to API
generateContent(args.prompt)
.then(response => {
assistRef.current?.addResponse(response);
})
.catch(error => {
assistRef.current?.addResponse(`Error: ${error.message}`);
})
.finally(() => {
setIsProcessing(false);
});
};
const handlePopupOpen = () => {
// Focus input
const input = document.querySelector('.e-aiassist-input') as HTMLElement;
input?.focus();
};
const handlePopupClose = () => {
console.log('Content generator closed');
};
return (
<InlineAIAssistComponent
ref={assistRef}
created={handleCreated}
promptRequest={handlePromptRequest}
open={handlePopupOpen}
close={handlePopupClose}
/>
);
};Example 2: Analytics and Monitoring
const MonitoredAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const startTimeRef = React.useRef<number>(0);
const handleCreated = () => {
analytics.log('assist_created', { timestamp: Date.now() });
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
startTimeRef.current = Date.now();
analytics.log('prompt_submitted', {
promptLength: args.prompt.length,
timestamp: Date.now()
});
processPrompt(args.prompt).then(response => {
const duration = Date.now() - startTimeRef.current;
assistRef.current?.addResponse(response);
analytics.log('response_generated', {
duration,
responseLength: response.length
});
});
};
const handlePopupOpen = () => {
analytics.log('popup_opened', { timestamp: Date.now() });
};
const handlePopupClose = () => {
analytics.log('popup_closed', { timestamp: Date.now() });
};
return (
<InlineAIAssistComponent
ref={assistRef}
created={handleCreated}
promptRequest={handlePromptRequest}
open={handlePopupOpen}
close={handlePopupClose}
/>
);
};Example 3: Multi-Language Support
const MultiLanguageAssistant: React.FC = () => {
const [language, setLanguage] = React.useState('en');
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handleCreated = () => {
// Load localized strings
loadLocalization(language);
};
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
// Add language context to prompt
const enhancedPrompt = `Language: ${language}\n\n${args.prompt}`;
callAI(enhancedPrompt).then(response => {
assistRef.current?.addResponse(response);
});
};
return (
<InlineAIAssistComponent
ref={assistRef}
created={handleCreated}
promptRequest={handlePromptRequest}
/>
);
};Best Practices
1. Error Handling: Wrap event handlers in try-catch 2. Async Operations: Use async/await for API calls 3. Cleanup: Remove listeners on component unmount 4. Logging: Track important events for debugging 5. Performance: Keep event handlers lightweight 6. User Feedback: Show loading states during processing 7. Analytics: Log user interactions for insights 8. Accessibility: Announce major events to screen readers
Getting Started with Inline AI Assist
Table of Contents
Installation
Install Syncfusion Package
Install the interactive chat package that contains Inline AI Assist:
npm install @syncfusion/ej2-react-interactive-chat --saveThis single command installs all required dependencies automatically.
CSS Theme Setup
Import the required CSS theme files in your main src/App.css or src/index.css. Choose one of the available themes:
Material Theme (Recommended for most apps)
@import "../node_modules/@syncfusion/ej2-base/styles/material.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/material.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/material.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/material.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/material.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/material.css";
@import "../node_modules/@syncfusion/ej2-react-interactive-chat/styles/material.css";Bootstrap Theme
@import "../node_modules/@syncfusion/ej2-base/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/bootstrap.css";
@import "../node_modules/@syncfusion/ej2-react-interactive-chat/styles/bootstrap.css";Fluent Theme
@import "../node_modules/@syncfusion/ej2-base/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/fluent.css";
@import "../node_modules/@syncfusion/ej2-react-interactive-chat/styles/fluent.css";Tailwind Theme
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-inputs/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-dropdowns/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind.css";
@import "../node_modules/@syncfusion/ej2-react-interactive-chat/styles/tailwind.css";Tip: Only import one theme. Importing multiple themes can cause CSS conflicts. All components automatically inherit the active theme.
Basic Component Rendering
Minimal Example (JavaScript)
Create a functional component and render Inline AI Assist:
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return (
<InlineAIAssistComponent id="inlineAiAssist"></InlineAIAssistComponent>
);
}
ReactDOM.render(<App />, document.getElementById('root'));Minimal Example (TypeScript)
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
import ReactDOM from 'react-dom';
const App: React.FC = () => {
return (
<InlineAIAssistComponent id="inlineAiAssist"></InlineAIAssistComponent>
);
};
ReactDOM.render(<App />, document.getElementById('root'));With Event Handlers
import { InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = (args: InlinePromptRequestEventArgs) => {
console.log('User prompt:', args.prompt);
// Simulate AI processing
setTimeout(() => {
const aiResponse = 'Your AI-generated response';
assistRef.current?.addResponse(aiResponse);
}, 1000);
};
return (
<InlineAIAssistComponent
ref={assistRef}
promptRequest={handlePromptRequest}
/>
);
};
export default App;Running Your Application
After setup, start the development server:
npm startThe app opens automatically at http://localhost:3000. You should see the Inline AI Assist component ready to use.
Verify Installation
Once running, check that: 1. ✅ Component renders without errors in browser console 2. ✅ Styles are applied correctly (buttons, inputs have proper styling) 3. ✅ Component is interactive (can type in prompt field)
Custom Styling with cssClass
The cssClass property allows you to apply custom CSS classes to the root element of the Inline AI Assist component for styling customization.
Property Details
Type: string Default: '' Component Property: cssClass
Basic Usage
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
return (
<InlineAIAssistComponent
cssClass="custom-ai-assist"
/>
);
};
export default App;Applying Multiple Classes
Use space-separated class names for multiple custom classes:
<InlineAIAssistComponent
cssClass="custom-theme dark-mode elevated"
/>Example: Custom Theme Colors
CSS (in your App.css or styles.css):
/* Custom blue theme */
.blue-theme .e-aiassist-input {
border-color: #2563eb;
background-color: #eff6ff;
}
.blue-theme .e-btn.e-primary {
background-color: #2563eb;
border-color: #2563eb;
}
.blue-theme .e-btn.e-primary:hover {
background-color: #1d4ed8;
}
.blue-theme .e-popup {
border: 2px solid #2563eb;
border-radius: 12px;
}Component:
<InlineAIAssistComponent
cssClass="blue-theme"
popupWidth="500px"
/>Example: Dark Mode Styling
/* Dark mode styles */
.dark-mode-assist {
--bg-color: #1f2937;
--text-color: #f9fafb;
--border-color: #374151;
}
.dark-mode-assist .e-aiassist-input {
background-color: var(--bg-color);
color: var(--text-color);
border-color: var(--border-color);
}
.dark-mode-assist .e-popup {
background-color: var(--bg-color);
color: var(--text-color);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}
.dark-mode-assist .e-btn {
background-color: #374151;
color: var(--text-color);
border-color: var(--border-color);
}Component:
<InlineAIAssistComponent
cssClass="dark-mode-assist"
/>Example: Compact Size Variant
/* Compact size */
.compact-assist .e-aiassist-input {
padding: 8px 12px;
font-size: 13px;
min-height: 80px;
}
.compact-assist .e-btn {
padding: 6px 14px;
font-size: 12px;
}
.compact-assist .e-popup {
max-width: 350px;
}Component:
<InlineAIAssistComponent
cssClass="compact-assist"
popupWidth="350px"
/>Example: Elevated Card Style
/* Elevated card effect */
.elevated-assist {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
border-radius: 12px;
padding: 20px;
background: white;
}
.elevated-assist .e-popup {
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.15);
border-radius: 16px;
border: 1px solid #e5e7eb;
}
.elevated-assist .e-aiassist-input {
border-radius: 8px;
border: 2px solid #e5e7eb;
transition: border-color 0.2s ease;
}
.elevated-assist .e-aiassist-input:focus {
border-color: #3b82f6;
outline: none;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}Component:
<InlineAIAssistComponent
cssClass="elevated-assist"
/>Best Practices for cssClass
1. Use Specific Class Names: Avoid generic names that might conflict with other styles
// Good
cssClass="my-app-ai-assist"
// Avoid
cssClass="container"2. CSS Specificity: Your custom classes should be specific enough to override default styles
/* Good - specific selector */
.my-app-ai-assist .e-aiassist-input {
/* styles */
}
/* May not work - too generic */
.e-aiassist-input {
/* styles */
}3. Use CSS Variables: For flexible theming across your app
.custom-theme {
--primary-color: #3b82f6;
--secondary-color: #8b5cf6;
--border-radius: 8px;
}
.custom-theme .e-btn.e-primary {
background-color: var(--primary-color);
}4. Test Across Themes: If using multiple Syncfusion themes, test your custom CSS with each
// Test with Material, Bootstrap, Fluent, etc.
<InlineAIAssistComponent cssClass="custom-theme" />5. Maintain Accessibility: Ensure custom colors meet WCAG contrast requirements
/* Ensure sufficient contrast */
.custom-theme .e-btn {
background-color: #2563eb; /* Blue */
color: #ffffff; /* White - good contrast */
}Common Customization Scenarios
Scenario 1: Match Brand Colors
.brand-ai-assist {
--brand-primary: #ff6b35;
--brand-secondary: #004e89;
}
.brand-ai-assist .e-btn.e-primary {
background-color: var(--brand-primary);
border-color: var(--brand-primary);
}
.brand-ai-assist .e-popup {
border-top: 4px solid var(--brand-primary);
}Scenario 2: Responsive Sizing
.responsive-assist .e-popup {
width: 90vw;
max-width: 600px;
}
@media (max-width: 768px) {
.responsive-assist .e-popup {
width: 95vw;
}
.responsive-assist .e-aiassist-input {
font-size: 16px; /* Prevents zoom on mobile */
}
}Scenario 3: Animation Effects
.animated-assist .e-popup {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}Complete Example: Full Custom Theme
CSS:
/* Custom professional theme */
.professional-ai-assist {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.professional-ai-assist .e-aiassist-input {
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 14px 16px;
font-size: 15px;
line-height: 1.5;
transition: all 0.2s ease;
background: #ffffff;
}
.professional-ai-assist .e-aiassist-input:focus {
border-color: #3b82f6;
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
}
.professional-ai-assist .e-popup {
border: 1px solid #e2e8f0;
border-radius: 12px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
overflow: hidden;
}
.professional-ai-assist .e-btn.e-primary {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
border: none;
border-radius: 6px;
padding: 10px 20px;
font-weight: 600;
letter-spacing: 0.3px;
transition: transform 0.2s ease;
}
.professional-ai-assist .e-btn.e-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
}Component:
const ProfessionalAssistant: React.FC = () => {
return (
<div className="app-container">
<h2>AI Writing Assistant</h2>
<InlineAIAssistComponent
cssClass="professional-ai-assist"
placeholder="Describe what you'd like to create..."
popupWidth="600px"
/>
</div>
);
};Common Setup Issues
Issue: CSS Not Applied (Components Look Unstyled)
Solution: Verify CSS imports are in the correct file (App.css or index.css) and the import path matches your node_modules location:
/* Make sure path is correct */
@import "../node_modules/@syncfusion/ej2-react-interactive-chat/styles/material.css";Issue: Module Not Found Error
Solution: Ensure the package is installed:
npm install @syncfusion/ej2-react-interactive-chat --save
npm install # Reinstall if neededIssue: Port 3000 Already in Use
Solution: Specify a different port:
PORT=3001 npm startIssue: React Version Compatibility
The component requires React 16.8+. Check your React version:
npm list reactIssue: Custom Styles Not Applying
Solution: Check CSS specificity and ensure your custom CSS is loaded after Syncfusion's CSS:
// In index.tsx or App.tsx
import '@syncfusion/ej2-react-interactive-chat/styles/material.css'; // First
import './App.css'; // Then your custom CSSInline Toolbar Customization
Table of Contents
- Overview
- Built-in Toolbar Items
- Toolbar Item Properties
- Item Types
- Configuring Toolbar Items
- Toolbar Positioning
- Tab Navigation
- Custom Templates
- Event Handling
- Complete Examples
Overview
The inline toolbar appears at the bottom of the prompt input area. By default, it contains a "Send" button. You can customize it by adding custom buttons, separators, input fields, or even custom templates for more complex interactions.
Toolbar configuration uses the inlineToolbarSettings property with the InlineToolbarSettingsModel interface.
Built-in Toolbar Items
The component includes one built-in toolbar item by default:
| Item | Type | Action | Purpose |
|---|---|---|---|
send | Button | Submits prompt | Triggers the promptRequest event |
This send button appears automatically in all modes.
Toolbar Item Properties
Each toolbar item (custom or modified) supports these properties:
| Property | Type | Enum | Description |
|---|---|---|---|
id | string | - | Unique identifier for the item |
text | string | - | Display text (for buttons, labels) |
iconCss | string | - | CSS class for icon display |
type | string | Button, Separator, Input | Item type determines rendering |
visible | boolean | - | Show/hide item (default: true) |
disabled | boolean | - | Enable/disable interaction |
align | string | Left, Center, Right | Horizontal alignment |
tooltip | string | - | Tooltip on hover |
cssClass | string | - | Additional CSS classes |
tabIndex | number | - | Tab key navigation order |
template | string \ | React.Component | - |
Item Types
Type: Button
Standard clickable button:
{
id: 'clear',
text: 'Clear',
type: 'Button',
iconCss: 'e-icons e-close'
}Type: Separator
Visual separator between items:
{
type: 'Separator'
}Type: Input
Input field for user interaction:
{
id: 'max-tokens',
type: 'Input',
text: 'Max tokens'
}Configuring Toolbar Items
Basic Toolbar Customization
import { InlineAIAssistComponent, InlineToolbarSettingsModel } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'save-prompt',
text: 'Save',
type: 'Button',
iconCss: 'e-icons e-save',
tooltip: 'Save this prompt for later'
},
{
id: 'history',
text: 'History',
type: 'Button',
iconCss: 'e-icons e-history',
tooltip: 'View prompt history'
},
{
type: 'Separator'
},
{
id: 'settings',
text: 'Settings',
type: 'Button',
iconCss: 'e-icons e-settings',
align: 'Right'
}
]
};
return (
<InlineAIAssistComponent inlineToolbarSettings={inlineToolbarSettings} />
);
};
export default App;Toolbar Items with Icons
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'bold',
iconCss: 'e-icons e-bold',
type: 'Button',
tooltip: 'Bold'
},
{
id: 'italic',
iconCss: 'e-icons e-italic',
type: 'Button',
tooltip: 'Italic'
},
{
id: 'underline',
iconCss: 'e-icons e-underline',
type: 'Button',
tooltip: 'Underline'
},
{
type: 'Separator'
},
{
id: 'clear-format',
text: 'Clear',
type: 'Button',
iconCss: 'e-icons e-close'
}
]
};Conditional Visibility
const App: React.FC = () => {
const [isLoggedIn, setIsLoggedIn] = React.useState(false);
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'save',
text: 'Save',
type: 'Button',
visible: isLoggedIn // Only show if logged in
},
{
id: 'clear',
text: 'Clear',
type: 'Button'
}
]
};
return (
<InlineAIAssistComponent inlineToolbarSettings={inlineToolbarSettings} />
);
};Disabling Toolbar Items
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'undo',
text: 'Undo',
type: 'Button',
disabled: true // Button is disabled
},
{
id: 'redo',
text: 'Redo',
type: 'Button',
disabled: false
}
]
};Toolbar Positioning
Control where the toolbar appears using the toolbarPosition property:
Position: Inline (Default)
Toolbar items render inline with the input field:
const inlineToolbarSettings: InlineToolbarSettingsModel = {
toolbarPosition: 'Inline', // or omit (default)
items: [
{ id: 'btn1', text: 'Button 1', type: 'Button' }
]
};Appearance: Buttons appear in same row as input, compact layout
Position: Bottom
Toolbar renders in a dedicated footer area below the input:
const inlineToolbarSettings: InlineToolbarSettingsModel = {
toolbarPosition: 'Bottom',
items: [
{ id: 'save', text: 'Save', type: 'Button' },
{ id: 'cancel', text: 'Cancel', type: 'Button' }
]
};Appearance: Full-width footer bar with buttons
Choosing Positions
const inlineToolbarSettings: InlineToolbarSettingsModel = {
toolbarPosition: 'Bottom', // Use when you have many toolbar items
items: [
{ id: 'save', text: 'Save' },
{ id: 'draft', text: 'Draft' },
{ id: 'preview', text: 'Preview' },
{ id: 'settings', text: 'Settings' },
{ id: 'help', text: 'Help' }
]
};Tab Navigation
Enable keyboard navigation using Tab key with the tabIndex property:
Basic Tab Navigation
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'button1',
text: 'First Button',
type: 'Button',
tabIndex: 1 // First in tab order
},
{
id: 'button2',
text: 'Second Button',
type: 'Button',
tabIndex: 2 // Second in tab order
}
]
};Tab Navigation Rules
- Positive tabIndex: Follows specified order (1, 2, 3...)
- tabIndex: 0: Uses DOM order for navigation
- Negative tabIndex: Item not in tab order (keyboard inaccessible)
- No tabIndex: Default behavior (uses DOM order)
Example: Custom Tab Order
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'save',
text: 'Save',
tabIndex: 1 // First focus
},
{
id: 'cancel',
text: 'Cancel',
tabIndex: 2 // Second focus
},
{
id: 'help',
text: 'Help',
tabIndex: 3 // Third focus
}
]
};Custom Templates
Use the template property for complex item rendering:
String Template
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'custom-btn',
template: '<button class="e-btn e-small"><span class="e-icons">✨</span> AI</button>'
}
]
};React Component Template
const CustomToolbarItem: React.FC = () => {
return (
<button className="e-btn e-small">
<span>⚡</span> Quick Action
</button>
);
};
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'custom-item',
template: <CustomToolbarItem />
}
]
};Template with State
const App: React.FC = () => {
const [promptCount, setPromptCount] = React.useState(0);
const PromptCounterTemplate: React.FC = () => {
return (
<span className="prompt-counter">
Prompts: {promptCount}
</span>
);
};
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'counter',
template: <PromptCounterTemplate />
}
]
};
return (
<InlineAIAssistComponent inlineToolbarSettings={inlineToolbarSettings} />
);
};Event Handling
Handle toolbar item clicks using the itemClick event:
ToolbarItemClickEventArgs Properties
The itemClick event provides detailed information about the clicked toolbar item:
interface ToolbarItemClickEventArgs {
cancel: boolean; // Set to true to cancel the default action
dataIndex: number; // Index of the message data (not applicable for inline toolbar)
event: Event; // Native browser click event
item: ToolbarItemModel; // The toolbar item that was clicked
name: string; // Event name ('itemClick')
}Property Details
| Property | Type | Description |
|---|---|---|
cancel | boolean | Set to true to prevent default toolbar item action. Default: false |
dataIndex | number | Index of associated message data. Note: Not applicable for inline toolbar items (always undefined in this context) |
event | Event | Native browser event object for the click |
item | ToolbarItemModel | Complete toolbar item model including id, text, iconCss, etc. |
name | string | Name of the event, always 'itemClick' |
Basic Item Click Handler
import { ToolbarItemClickEventArgs } from '@syncfusion/ej2-react-interactive-chat';
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
console.log('Toolbar item clicked:', args.item.id);
console.log('Item text:', args.item.text);
console.log('Event name:', args.name);
};
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{ id: 'save', text: 'Save', type: 'Button' }
],
itemClick: handleToolbarItemClick
};
<InlineAIAssistComponent inlineToolbarSettings={inlineToolbarSettings} />Using cancel Property
Prevent the default action by setting cancel to true:
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Validate before allowing action
if (args.item.id === 'submit' && !isFormValid()) {
args.cancel = true; // Prevent default action
alert('Please fill all required fields');
return;
}
// Proceed with action
processToolbarAction(args.item.id);
};Using event Property
Access the native browser event for advanced scenarios:
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Check modifier keys
if (args.event instanceof MouseEvent) {
if (args.event.ctrlKey) {
console.log('Ctrl + Click detected');
openInNewTab(args.item.id);
return;
}
if (args.event.shiftKey) {
console.log('Shift + Click detected');
selectMultiple(args.item.id);
return;
}
}
// Get click coordinates
const clickX = (args.event as MouseEvent).clientX;
const clickY = (args.event as MouseEvent).clientY;
console.log(`Clicked at: (${clickX}, ${clickY})`);
// Normal click
handleNormalClick(args.item.id);
};Using item Property
Access complete toolbar item details:
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
const { item } = args;
console.log('Item ID:', item.id);
console.log('Item Text:', item.text);
console.log('Item Type:', item.type);
console.log('Item Icon:', item.iconCss);
console.log('Item Disabled:', item.disabled);
console.log('Item Tooltip:', item.tooltip);
// Use item properties for conditional logic
if (item.disabled) {
console.log('Item is disabled, should not trigger');
return;
}
// Execute action based on item type
if (item.type === 'Button') {
executeButtonAction(item.id);
}
};Using name Property
Check event type for multi-event handlers:
const handleToolbarEvent = (args: ToolbarItemClickEventArgs) => {
// Verify it's an itemClick event
if (args.name === 'itemClick') {
console.log('Item click event confirmed');
processItemClick(args.item);
}
// Log event name for debugging
console.log(`Event triggered: ${args.name}`);
};Complete Event Args Example
const CompleteEventExample: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const [clickLog, setClickLog] = React.useState<string[]>([]);
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Log all event properties
const logEntry = `
Event: ${args.name}
Item ID: ${args.item.id}
Item Text: ${args.item.text}
Cancelled: ${args.cancel}
DataIndex: ${args.dataIndex}
Event Type: ${args.event.type}
Timestamp: ${new Date().toLocaleTimeString()}
`;
setClickLog(prev => [logEntry, ...prev]);
// Conditional cancellation
if (args.item.id === 'delete') {
const confirmed = confirm('Are you sure you want to delete?');
if (!confirmed) {
args.cancel = true; // Cancel the action
return;
}
}
// Handle based on modifier keys
if (args.event instanceof MouseEvent) {
if (args.event.ctrlKey && args.item.id === 'open') {
console.log('Opening in new window...');
args.cancel = true; // Prevent default, handle custom
window.open('/new-window', '_blank');
return;
}
}
// Normal processing
console.log(`Processing: ${args.item.id}`);
};
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{ id: 'save', text: 'Save', type: 'Button' },
{ id: 'open', text: 'Open', type: 'Button' },
{ id: 'delete', text: 'Delete', type: 'Button' }
],
itemClick: handleToolbarItemClick
};
return (
<div>
<InlineAIAssistComponent
ref={assistRef}
inlineToolbarSettings={inlineToolbarSettings}
/>
<div className="event-log">
<h4>Event Log:</h4>
{clickLog.map((log, index) => (
<pre key={index}>{log}</pre>
))}
</div>
</div>
);
};Advanced Click Handler with Logic
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Access all properties
const { item, event, cancel, name, dataIndex } = args;
console.log(`Event: ${name}`);
console.log(`Item: ${item.id}`);
console.log(`DataIndex: ${dataIndex}`); // undefined for inline toolbar
switch (item.id) {
case 'save':
saveCurrentPrompt();
break;
case 'clear':
clearInput();
break;
case 'history':
showPromptHistory();
break;
default:
console.log('Unknown toolbar action');
}
};Validation Example
const ValidationExample: React.FC = () => {
const [isValid, setIsValid] = React.useState(false);
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Prevent submission if validation fails
if (args.item.id === 'submit' && !isValid) {
args.cancel = true;
alert('Form validation failed. Please check your input.');
return;
}
// Confirm dangerous actions
if (args.item.id === 'reset') {
const confirmed = confirm('This will reset all data. Continue?');
if (!confirmed) {
args.cancel = true;
return;
}
}
// Proceed with action
console.log(`Action: ${args.item.id}`);
};
return (
<InlineAIAssistComponent
inlineToolbarSettings={{
items: [
{ id: 'submit', text: 'Submit', type: 'Button' },
{ id: 'reset', text: 'Reset', type: 'Button' }
],
itemClick: handleToolbarItemClick
}}
/>
);
};Analytics Tracking Example
const AnalyticsExample: React.FC = () => {
const handleToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
// Track to analytics
analytics.track('toolbar_item_clicked', {
itemId: args.item.id,
itemText: args.item.text,
eventName: args.name,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
});
// Log click position for heatmap
if (args.event instanceof MouseEvent) {
heatmap.track({
x: args.event.clientX,
y: args.event.clientY,
element: args.item.id
});
}
// Normal action handling
processToolbarAction(args.item.id);
};
return (
<InlineAIAssistComponent
inlineToolbarSettings={{
items: [
{ id: 'action1', text: 'Action 1', type: 'Button' },
{ id: 'action2', text: 'Action 2', type: 'Button' }
],
itemClick: handleToolbarItemClick
}}
/>
);
};Complete Examples
Example 1: Content Editor Toolbar
const ContentEditor: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const inlineToolbarSettings: InlineToolbarSettingsModel = {
toolbarPosition: 'Bottom',
items: [
{
id: 'format-bold',
iconCss: 'e-icons e-bold',
type: 'Button',
tooltip: 'Bold',
align: 'Left'
},
{
id: 'format-italic',
iconCss: 'e-icons e-italic',
type: 'Button',
tooltip: 'Italic'
},
{
type: 'Separator'
},
{
id: 'clear',
text: 'Clear',
type: 'Button',
align: 'Right'
},
{
id: 'submit',
text: 'Submit',
type: 'Button',
align: 'Right'
}
],
itemClick: (args) => {
switch (args.item.id) {
case 'format-bold':
document.execCommand('bold');
break;
case 'format-italic':
document.execCommand('italic');
break;
case 'clear':
assistRef.current?.hidePopup();
break;
case 'submit':
assistRef.current?.showPopup();
break;
}
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
inlineToolbarSettings={inlineToolbarSettings}
/>
);
};Example 2: Development Assistant Toolbar
const CodeAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'format-json',
text: 'Format JSON',
type: 'Button',
iconCss: 'e-icons e-settings'
},
{
id: 'validate',
text: 'Validate',
type: 'Button',
iconCss: 'e-icons e-check-box'
},
{
type: 'Separator'
},
{
id: 'minify',
text: 'Minify',
type: 'Button',
align: 'Right'
}
],
itemClick: (args) => {
if (args.item.id === 'format-json') {
assistRef.current?.executePrompt('Format this JSON code');
} else if (args.item.id === 'validate') {
assistRef.current?.executePrompt('Validate this code');
}
}
};
return (
<InlineAIAssistComponent
ref={assistRef}
inlineToolbarSettings={inlineToolbarSettings}
/>
);
};Example 3: Input Field Toolbar
const PromptWithSettings: React.FC = () => {
const inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'temperature',
text: 'Temperature',
type: 'Input'
},
{
type: 'Separator'
},
{
id: 'quick-prompt',
text: 'Quick',
type: 'Button',
iconCss: 'e-icons e-lightning'
},
{
id: 'detailed-prompt',
text: 'Detailed',
type: 'Button',
iconCss: 'e-icons e-list'
}
]
};
return (
<InlineAIAssistComponent inlineToolbarSettings={inlineToolbarSettings} />
);
};Best Practices
1. Clear Icons: Use consistent Syncfusion icon set 2. Descriptive Tooltips: Help users understand button purpose 3. Logical Grouping: Use separators to organize related items 4. Alignment: Use align: 'Right' for secondary actions 5. Tab Order: Set tabIndex for important interactive items 6. Responsive: Consider mobile devices (fewer items, larger buttons) 7. Accessibility: Always include tooltips for icon-only buttons 8. Performance: Avoid complex templates in toolbar items 9. Consistency: Match your app's design language 10. User Feedback: Visual feedback when items are clicked
````markdown
Internationalization (i18n) and RTL Support
Table of Contents
- Overview
- locale Property
- enableRtl Property
- Combining locale and enableRtl
- Available Locales
- Custom Localization
- Complete Examples
Overview
The Inline AI Assist component supports internationalization (i18n) and right-to-left (RTL) text direction for building global applications. Two key properties enable this:
1. locale - Sets the language and regional formatting 2. enableRtl - Enables right-to-left text direction
These properties ensure your AI assistant can serve users worldwide with proper localization and text directionality.
locale Property
The locale property sets the language and cultural formatting for the component's UI text, date formats, and number formats.
Property Details
Type: string Default: 'en-US' Component Property: locale
Supported Locale Codes
Locale codes follow the BCP 47 format: language-REGION (e.g., en-US, fr-FR, ar-SA)
Basic Usage
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
return (
<InlineAIAssistComponent
locale="fr-FR"
placeholder="Demandez à l'IA..."
/>
);
};
export default App;What Gets Localized
When you set the locale property, the following UI elements adapt:
1. UI Text:
- Button labels (Send, Cancel, Accept, Reject)
- Placeholder text
- Error messages
- Tooltips
2. Date/Time Formatting:
- Timestamps in response headers
- Date displays in metadata
3. Number Formatting:
- Character counts
- Token counts
- Progress indicators
Setting Up Localization
Step 1: Install Localization Package
npm install @syncfusion/ej2-locale --saveStep 2: Import Locale Data
import { L10n, loadCldr } from '@syncfusion/ej2-base';
import * as numberingSystems from 'cldr-data/supplemental/numberingSystems.json';
import * as gregorian from 'cldr-data/main/fr-FR/ca-gregorian.json';
import * as numbers from 'cldr-data/main/fr-FR/numbers.json';
import * as timeZoneNames from 'cldr-data/main/fr-FR/timeZoneNames.json';
// Load CLDR data
loadCldr(numberingSystems, gregorian, numbers, timeZoneNames);Step 3: Define Localized Strings
// French localization
L10n.load({
'fr-FR': {
'inline-ai-assist': {
'placeholder': 'Demandez quelque chose à l\'IA...',
'send': 'Envoyer',
'cancel': 'Annuler',
'accept': 'Accepter',
'reject': 'Rejeter',
'generating': 'Génération en cours...',
'error': 'Une erreur s\'est produite'
}
}
});Step 4: Apply Locale to Component
const App: React.FC = () => {
return (
<InlineAIAssistComponent
locale="fr-FR"
/>
);
};Complete Localization Example
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { L10n } from '@syncfusion/ej2-base';
import React from 'react';
// Define Spanish localization
L10n.load({
'es-ES': {
'inline-ai-assist': {
'placeholder': 'Pregunta algo a la IA...',
'send': 'Enviar',
'cancel': 'Cancelar',
'accept': 'Aceptar',
'reject': 'Rechazar',
'regenerate': 'Regenerar',
'copy': 'Copiar',
'generating': 'Generando respuesta...',
'error': 'Se produjo un error',
'noResponse': 'No se recibió respuesta'
}
}
});
const SpanishAssistant: React.FC = () => {
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = (args: any) => {
setTimeout(() => {
assistRef.current?.addResponse('Esta es una respuesta de la IA.');
}, 1000);
};
return (
<InlineAIAssistComponent
ref={assistRef}
locale="es-ES"
promptRequest={handlePromptRequest}
/>
);
};
export default SpanishAssistant;enableRtl Property
The enableRtl property enables right-to-left text direction for languages like Arabic, Hebrew, Persian, and Urdu.
Property Details
Type: boolean Default: false Component Property: enableRtl
When to Use
Enable RTL when your application serves:
- Arabic (ar)
- Hebrew (he)
- Persian/Farsi (fa)
- Urdu (ur)
- Other RTL languages
Basic Usage
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import React from 'react';
const App: React.FC = () => {
return (
<InlineAIAssistComponent
enableRtl={true}
placeholder="اسأل الذكاء الاصطناعي..."
/>
);
};
export default App;What Changes with RTL
When enableRtl is enabled:
1. Layout Direction:
- Component layout flips horizontally
- Buttons move from right to left
- Text alignment changes to right
2. UI Elements:
- Input fields align text to the right
- Icons and buttons reposition to the left
- Popup menus open from right to left
3. Scroll Behavior:
- Scrollbars appear on the left side
- Scroll direction adjusts accordingly
RTL Example (Arabic)
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { L10n } from '@syncfusion/ej2-base';
import React from 'react';
// Arabic localization
L10n.load({
'ar-SA': {
'inline-ai-assist': {
'placeholder': 'اسأل الذكاء الاصطناعي...',
'send': 'إرسال',
'cancel': 'إلغاء',
'accept': 'قبول',
'reject': 'رفض',
'generating': 'جارٍ الإنشاء...',
'error': 'حدث خطأ'
}
}
});
const ArabicAssistant: React.FC = () => {
return (
<div dir="rtl"> {/* Set RTL on container */}
<InlineAIAssistComponent
locale="ar-SA"
enableRtl={true}
/>
</div>
);
};
export default ArabicAssistant;RTL Example (Hebrew)
// Hebrew localization
L10n.load({
'he-IL': {
'inline-ai-assist': {
'placeholder': 'שאל את הבינה המלאכותית...',
'send': 'שלח',
'cancel': 'ביטול',
'accept': 'אשר',
'reject': 'דחה',
'generating': 'מייצר תשובה...',
'error': 'אירעה שגיאה'
}
}
});
const HebrewAssistant: React.FC = () => {
return (
<InlineAIAssistComponent
locale="he-IL"
enableRtl={true}
/>
);
};Combining locale and enableRtl
For RTL languages, you typically use both properties together:
Complete RTL Setup
import { InlineAIAssistComponent } from '@syncfusion/ej2-react-interactive-chat';
import { L10n } from '@syncfusion/ej2-base';
import React from 'react';
const RTLAssistant: React.FC = () => {
// Setup Arabic localization
React.useEffect(() => {
L10n.load({
'ar-SA': {
'inline-ai-assist': {
'placeholder': 'اسأل الذكاء الاصطناعي...',
'send': 'إرسال',
'cancel': 'إلغاء',
'accept': 'قبول',
'reject': 'رفض'
}
}
});
}, []);
const assistRef = React.useRef<InlineAIAssistComponent>(null);
const handlePromptRequest = (args: any) => {
// Call Arabic AI service
callArabicAI(args.prompt).then(response => {
assistRef.current?.addResponse(response);
});
};
return (
<div dir="rtl" style={{ fontFamily: 'Arial, sans-serif' }}>
<h2>مساعد الذكاء الاصطناعي</h2>
<InlineAIAssistComponent
ref={assistRef}
locale="ar-SA"
enableRtl={true}
promptRequest={handlePromptRequest}
popupWidth="500px"
/>
</div>
);
};
export default RTLAssistant;Available Locales
Common Locales
| Locale Code | Language | Region | RTL Required |
|---|---|---|---|
en-US | English | United States | No |
en-GB | English | United Kingdom | No |
es-ES | Spanish | Spain | No |
es-MX | Spanish | Mexico | No |
fr-FR | French | France | No |
de-DE | German | Germany | No |
it-IT | Italian | Italy | No |
pt-BR | Portuguese | Brazil | No |
pt-PT | Portuguese | Portugal | No |
ru-RU | Russian | Russia | No |
ja-JP | Japanese | Japan | No |
ko-KR | Korean | South Korea | No |
zh-CN | Chinese | China (Simplified) | No |
zh-TW | Chinese | Taiwan (Traditional) | No |
ar-SA | Arabic | Saudi Arabia | Yes |
ar-AE | Arabic | UAE | Yes |
he-IL | Hebrew | Israel | Yes |
fa-IR | Persian | Iran | Yes |
ur-PK | Urdu | Pakistan | Yes |
hi-IN | Hindi | India | No |
bn-BD | Bengali | Bangladesh | No |
tr-TR | Turkish | Turkey | No |
pl-PL | Polish | Poland | No |
nl-NL | Dutch | Netherlands | No |
sv-SE | Swedish | Sweden | No |
da-DK | Danish | Denmark | No |
fi-FI | Finnish | Finland | No |
no-NO | Norwegian | Norway | No |
Custom Localization
Creating Custom Locale Strings
Define custom localization for any language:
import { L10n } from '@syncfusion/ej2-base';
// Define custom locale
L10n.load({
'custom-LANG': {
'inline-ai-assist': {
// Prompt input
'placeholder': 'Your placeholder text',
// Actions
'send': 'Send',
'cancel': 'Cancel',
'accept': 'Accept',
'reject': 'Reject',
'regenerate': 'Regenerate',
'copy': 'Copy',
'share': 'Share',
// Status messages
'generating': 'Generating...',
'loading': 'Loading...',
'processing': 'Processing...',
// Error messages
'error': 'An error occurred',
'noResponse': 'No response received',
'networkError': 'Network error',
'timeout': 'Request timed out',
// Tooltips
'sendTooltip': 'Send prompt',
'cancelTooltip': 'Cancel request',
'acceptTooltip': 'Accept response',
'rejectTooltip': 'Reject response'
}
}
});Multi-Language Application
Support multiple languages with language selector:
const MultiLanguageAssistant: React.FC = () => {
const [currentLocale, setCurrentLocale] = React.useState('en-US');
const [isRtl, setIsRtl] = React.useState(false);
const assistRef = React.useRef<InlineAIAssistComponent>(null);
// RTL languages
const rtlLanguages = ['ar-SA', 'he-IL', 'fa-IR', 'ur-PK'];
// Setup localizations
React.useEffect(() => {
L10n.load({
'en-US': {
'inline-ai-assist': {
'placeholder': 'Ask AI anything...',
'send': 'Send',
'cancel': 'Cancel',
'accept': 'Accept',
'reject': 'Reject'
}
},
'es-ES': {
'inline-ai-assist': {
'placeholder': 'Pregunta algo...',
'send': 'Enviar',
'cancel': 'Cancelar',
'accept': 'Aceptar',
'reject': 'Rechazar'
}
},
'ar-SA': {
'inline-ai-assist': {
'placeholder': 'اسأل الذكاء الاصطناعي...',
'send': 'إرسال',
'cancel': 'إلغاء',
'accept': 'قبول',
'reject': 'رفض'
}
},
'fr-FR': {
'inline-ai-assist': {
'placeholder': 'Demandez à l\'IA...',
'send': 'Envoyer',
'cancel': 'Annuler',
'accept': 'Accepter',
'reject': 'Rejeter'
}
}
});
}, []);
const handleLanguageChange = (locale: string) => {
setCurrentLocale(locale);
setIsRtl(rtlLanguages.includes(locale));
};
return (
<div dir={isRtl ? 'rtl' : 'ltr'}>
<div className="language-selector">
<label>Language:</label>
<select
value={currentLocale}
onChange={(e) => handleLanguageChange(e.target.value)}
className="e-input"
>
<option value="en-US">🇺🇸 English</option>
<option value="es-ES">🇪🇸 Español</option>
<option value="fr-FR">🇫🇷 Français</option>
<option value="ar-SA">🇸🇦 العربية</option>
</select>
</div>
<InlineAIAssistComponent
ref={assistRef}
locale={currentLocale}
enableRtl={isRtl}
/>
</div>
);
};Complete Examples
Example 1: Multi-Region Support
const GlobalAssistant: React.FC = () => {
const [region, setRegion] = React.useState<'us' | 'eu' | 'asia' | 'mena'>('us');
const regionSettings = {
us: { locale: 'en-US', rtl: false },
eu: { locale: 'de-DE', rtl: false },
asia: { locale: 'ja-JP', rtl: false },
mena: { locale: 'ar-SA', rtl: true }
};
const currentSettings = regionSettings[region];
React.useEffect(() => {
// Load all regional localizations
L10n.load({
'en-US': { /* English strings */ },
'de-DE': { /* German strings */ },
'ja-JP': { /* Japanese strings */ },
'ar-SA': { /* Arabic strings */ }
});
}, []);
return (
<div dir={currentSettings.rtl ? 'rtl' : 'ltr'}>
<div className="region-selector">
<button onClick={() => setRegion('us')}>🇺🇸 Americas</button>
<button onClick={() => setRegion('eu')}>🇪🇺 Europe</button>
<button onClick={() => setRegion('asia')}>🌏 Asia</button>
<button onClick={() => setRegion('mena')}>🌍 MENA</button>
</div>
<InlineAIAssistComponent
locale={currentSettings.locale}
enableRtl={currentSettings.rtl}
/>
</div>
);
};Example 2: Browser Language Detection
const AutoLocaleAssistant: React.FC = () => {
const [locale, setLocale] = React.useState('en-US');
const [enableRtl, setEnableRtl] = React.useState(false);
React.useEffect(() => {
// Detect browser language
const browserLang = navigator.language || navigator.languages[0];
// Map to supported locale
const supportedLocales: Record<string, string> = {
'en': 'en-US',
'es': 'es-ES',
'fr': 'fr-FR',
'de': 'de-DE',
'ar': 'ar-SA',
'he': 'he-IL',
'ja': 'ja-JP',
'zh': 'zh-CN'
};
const lang = browserLang.split('-')[0];
const detectedLocale = supportedLocales[lang] || 'en-US';
setLocale(detectedLocale);
setEnableRtl(['ar-SA', 'he-IL', 'fa-IR'].includes(detectedLocale));
}, []);
return (
<InlineAIAssistComponent
locale={locale}
enableRtl={enableRtl}
/>
);
};Example 3: User Preference Storage
const PersistentLocaleAssistant: React.FC = () => {
const [locale, setLocale] = React.useState<string>(() => {
// Load from localStorage
return localStorage.getItem('preferredLocale') || 'en-US';
});
const [enableRtl, setEnableRtl] = React.useState<boolean>(() => {
return localStorage.getItem('preferredRtl') === 'true';
});
const handleLocaleChange = (newLocale: string) => {
const isRtl = ['ar-SA', 'he-IL', 'fa-IR', 'ur-PK'].includes(newLocale);
setLocale(newLocale);
setEnableRtl(isRtl);
// Persist to localStorage
localStorage.setItem('preferredLocale', newLocale);
localStorage.setItem('preferredRtl', isRtl.toString());
};
return (
<div>
<select
value={locale}
onChange={(e) => handleLocaleChange(e.target.value)}
>
<option value="en-US">English (US)</option>
<option value="es-ES">Español</option>
<option value="fr-FR">Français</option>
<option value="ar-SA">العربية</option>
</select>
<InlineAIAssistComponent
locale={locale}
enableRtl={enableRtl}
/>
</div>
);
};Best Practices
Localization Best Practices
1. Provide Complete Translations:
- Translate all UI text, not just partial strings
- Include tooltips, error messages, and help text
2. Test with Native Speakers:
- Verify translations are culturally appropriate
- Check for proper grammar and context
3. Consider Text Expansion:
- Some languages require more space (German, Finnish)
- Design UI to accommodate text length variations
4. Use Standard Locale Codes:
- Follow BCP 47 format (language-REGION)
- Be consistent across your application
5. Date and Number Formatting:
- Use locale-aware formatting libraries
- Consider regional preferences (12/24 hour, date order)
RTL Best Practices
1. Test UI Layout:
- Verify all elements flip correctly
- Check alignment and spacing
2. Icons and Images:
- Some icons may need mirroring (arrows, directional icons)
- Logos usually don't need flipping
3. Mixed Content:
- Handle mixed LTR/RTL content gracefully
- Properly mark content directionality
4. Input Handling:
- Ensure proper text cursor behavior
- Test copy/paste functionality
5. Accessibility:
- Verify screen reader compatibility
- Test keyboard navigation
General i18n Guidelines
1. Avoid Hardcoded Text:
- Use L10n for all user-facing text
- Don't concatenate translated strings
2. Context Matters:
- Same word may need different translations in different contexts
- Provide context comments for translators
3. Pluralization:
- Handle plural forms correctly (some languages have multiple plural forms)
- Use ICU message format when needed
4. Cultural Sensitivity:
- Be aware of cultural differences in colors, symbols
- Test with users from target locales
5. Performance:
- Load only required locale data
- Consider lazy loading for large applications
---
````
Related skills
How it compares
Use syncfusion-react-inline-ai-assist for Syncfusion-native inline AI UI; use generic AI SDK skills when building assist features without Syncfusion components.
FAQ
What does syncfusion-react-inline-ai-assist implement?
syncfusion-react-inline-ai-assist implements Syncfusion inline AI assistance controls inside React applications. The skill covers component setup for contextual AI help embedded in editors, forms, or similar UI surfaces.
When should developers use syncfusion-react-inline-ai-assist?
syncfusion-react-inline-ai-assist fits React builds that already use Syncfusion and need embedded AI assistance without custom UI primitives. Use it during frontend integration when copilot-style inline help is required.