
Syncfusion Angular Inline Ai Assist
- 200 installs
- Updated August 4, 2026
- syncfusion/angular-ui-components-skills
Use syncfusion-angular-inline-ai-assist for development tasks
About
syncfusion-angular-inline-ai-assist: A skill for development. This provides functionality for development workflows.
- syncfusion-angular-inline-ai-assist
Syncfusion Angular Inline Ai Assist by the numbers
- 200 all-time installs (skills.sh)
- +5 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,977 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/angular-ui-components-skills --skill syncfusion-angular-inline-ai-assistAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 200 |
|---|---|
| Last updated | August 4, 2026 |
| Repository | syncfusion/angular-ui-components-skills ↗ |
What it does
Use syncfusion-angular-inline-ai-assist for development tasks
Files
Syncfusion Angular Inline AI Assist Component
Component Overview
The Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity. It leverages advanced natural language processing to enable AI-powered text suggestions, content generation, and editing features directly within Angular applications.
Key Capabilities:
- Response Modes - Popup (floating) or Inline (in-place) response display with configurable dimensions
- Command System - Predefined AI operations with icons, grouping, and custom command items
- Response Actions - Custom response toolbar items for accept/reject workflows
- Template System - Flexible editor and response templates for custom layouts
- Events & Interactions - Comprehensive events for lifecycle (created, open, close) and user interactions
- Toolbar Configuration - Inline toolbar with custom items, positioning, and alignment
- Methods - Programmatically add prompts, update responses, open/close popups, and control behavior
- Globalization - Multi-language support with RTL capabilities and locale-based formatting
- Customizable UI - CSS classes, z-index control, popup dimensions, and theme integration
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation and package setup
- Angular environment configuration
- Basic component implementation
- CSS imports and theme setup
- Initial configuration with relateTo and target properties
Core Configuration
📄 Read: references/core-configuration.md
- Prompt text and placeholder configuration
- Prompt/response collection management
- Response display modes (Popup vs Inline)
- Popup dimensions (width, height, z-index)
- CSS customization and styling
Commands and Responses
📄 Read: references/commands-and-responses.md
- Command settings and command items
- Adding preset AI operations with grouping
- Response settings and response items
- Built-in accept/reject actions
- Custom response toolbar items and event handling
Templates and Toolbars
📄 Read: references/templates-and-toolbars.md
- Editor template customization
- Response template layout
- Inline toolbar configuration and items
- Toolbar positioning, alignment, and styling
- Tab key navigation in toolbars
Events and Methods
📄 Read: references/events-and-methods.md
- Lifecycle events (created, open, close)
- Prompt request event handling
- Component methods (addResponse, executePrompt, showPopup, hidePopup)
- Event arguments and callback patterns
Localization and Styling
📄 Read: references/localization-and-styling.md
- Localization and multi-language support
- Right-to-left (RTL) text direction
- Custom CSS class styling
- Theme integration
- Text content customization
Quick Start Example
import { Component, ViewChild } from '@angular/core';
import { InlineAIAssistModule, InlineAIAssistComponent, InlinePromptRequestEventArgs, ResponseSettingsModel, ResponseItemSelectEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container" style="height: 350px; width: 650px;">
<button id="summarizeBtn" class="e-btn e-primary" (click)="onClick()">Content Summarize</button>
<div id="editableText" contenteditable="true">
<p>Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity.</p>
</div>
<ejs-inlineaiassist id="inlineAssist" #inlineAssistComponent
[relateTo]="'#summarizeBtn'"
[responseSettings]="responseSetting"
popupWidth="500px"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
const editable = document.getElementById('editableText') as HTMLElement;
if (editable && this.inlineAssistComponent.prompts.length > 0) {
const lastResponse = this.inlineAssistComponent.prompts[this.inlineAssistComponent.prompts.length - 1].response;
editable.innerHTML = '<p>' + lastResponse + '</p>';
}
this.inlineAssistComponent.hidePopup();
}
}
public responseSetting: ResponseSettingsModel = {
itemSelect: this.itemSelect
}
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
let response = 'Connect this component to OpenAI or Azure AI services for real-time prompt processing.';
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
}Common Patterns
Pattern 1: Response Handling with Item Selection
// Handle accept/reject responses
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
// Apply the AI response to your content
const content = this.inlineAssistComponent.prompts[this.inlineAssistComponent.prompts.length - 1].response;
this.applyResponse(content);
this.inlineAssistComponent.hidePopup();
} else if (args.command.label === 'Discard') {
this.inlineAssistComponent.hidePopup();
}
}Pattern 2: Executing Predefined Prompts
// Execute a specific prompt with custom command
public executeCommand(prompt: string) => {
this.inlineAssistComponent.showPopup();
this.inlineAssistComponent.executePrompt(prompt);
}
// Example usage: Summarize, Translate, or Make Professional
this.executeCommand('Summarize the content');Pattern 3: Command Groups for Organization
// Organize commands into logical groups
public commandSetting: CommandSettingsModel = {
commands: [
{ label: 'Summarize', prompt: 'Summarize...', groupBy: 'Improve content' },
{ label: 'Shorten', prompt: 'Shorten...', groupBy: 'Improve content' },
{ label: 'Translate', prompt: 'Translate...', groupBy: 'Edit content' },
]
}Pattern 4: Inline vs Popup Modes
// Toggle between response display modes
public responseMode: string = 'Popup'; // or 'Inline'
// Use Inline for seamless in-place editing
// Use Popup for review-based workflowsKey Properties and Configuration
| Property | Purpose | Example |
|---|---|---|
relateTo | Position relative to DOM element | [relateTo]="'#button'" |
target | Append location in DOM | [target]="'#container'" |
responseMode | Display mode (Popup/Inline) | [responseMode]="'Popup'" |
popupWidth / popupHeight | Popup dimensions | popupWidth="500px" |
placeholder | Prompt textarea placeholder | [placeholder]="'Ask AI...'" |
cssClass | Custom CSS styling | [cssClass]="'custom'" |
enableStreaming | Real-time streaming responses | [enableStreaming]="true" |
enablePersistence | Preserve state across reloads | [enablePersistence]="true" |
commandSettings | Predefined AI commands | [commandSettings]="cmdSettings" |
responseSettings | Response action items | [responseSettings]="respSettings" |
inlineToolbarSettings | Inline toolbar items | [inlineToolbarSettings]="toolbar" |
editorTemplate | Custom prompt input template | [editorTemplate]="template" |
responseTemplate | Custom response display template | [responseTemplate]="template" |
locale | Language/localization | [locale]="'de'" |
enableRtl | Right-to-left text direction | [enableRtl]="true" |
Common Use Cases
1. Text Summarization: Create a button that triggers content summarization via AI 2. Grammar & Style: Help users improve writing with grammar and style suggestions 3. Content Translation: Add quick translation options for multiple languages 4. Code Generation: Assist users in generating code snippets based on descriptions 5. Email Composition: Enhance email writing with AI suggestions and rephrasing 6. Document Enhancement: Improve document quality with AI-powered editing 7. Accessibility Support: Provide AI assistance for users with accessibility needs 8. Multilingual Support: Enable global applications with localized AI assistance
Commands and Responses Configuration
Table of Contents
- Command Settings
- Response Settings
- Built-in Items
- Command Item Properties
- Response Item Properties
- Event Handling
Command Settings
Overview
Commands are preset AI operations that users can quickly select from a popup menu. Each command has a label, prompt, and optional icon and grouping.
Configuring Command Items
Use the commandSettings property to define available commands:
import { CommandSettingsModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public commandSetting: CommandSettingsModel = {
commands: [
{
label: 'Summarize',
prompt: 'Summarize the content',
iconCss: 'e-icons e-collapse-2',
groupBy: 'Improve content',
tooltip: 'Summarize'
},
{
label: 'Shorten',
prompt: 'Shorten the content',
iconCss: 'e-icons e-shorten',
groupBy: 'Improve content',
tooltip: 'Shorten'
},
{
label: 'Translate',
prompt: 'Translate the content',
iconCss: 'e-icons e-translate',
groupBy: 'Edit content',
tooltip: 'Translate'
},
{
label: 'Make professional',
prompt: 'Make the content more professional',
iconCss: 'e-icons e-elaborate',
groupBy: 'Edit content'
}
]
};
}Command Popup Dimensions
Control the command popup size:
public commandSetting: CommandSettingsModel = {
commands: [...],
popupWidth: '300px',
popupHeight: '250px'
}Response Settings
Overview
Response items are action buttons shown after AI generates a response. Use them to accept, reject, copy, or regenerate responses.
Configuring Response Items
Use the responseSettings property to customize response actions:
import { ResponseSettingsModel, ResponseItemSelectEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public onItemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
// Apply response to content
this.applyResponse();
} else if (args.command.label === 'Copy') {
// Copy response to clipboard
this.copyToClipboard();
}
}
public responseSetting: ResponseSettingsModel = {
items: [
{
label: 'Regenerate',
iconCss: 'e-icons e-refresh',
tooltip: 'Regenerate the response',
groupBy: 'Actions'
},
{
label: 'Copy',
iconCss: 'e-icons e-copy',
tooltip: 'Copy the response',
groupBy: 'Actions'
}
],
itemSelect: this.onItemSelect
}
}Built-in Items
Built-in Commands
Default command groups include:
- Summarize, Shorten, Rephrase
- Translate to different languages
- Grammar & style improvements
- Tone adjustments (formal, casual, etc.)
Built-in Response Items
The component provides default response actions:
- Accept - Apply the AI-generated response
- Reject (Discard) - Dismiss the response
These are shown even if no custom items are configured.
Command Item Properties
Label
Visible text displayed in the command popup:
{ label: 'Summarize' }Prompt
The prompt text executed when command is selected:
{ label: 'Summarize', prompt: 'Summarize the content in 2-3 sentences' }ID (Optional)
Unique identifier for detecting selected command:
{ id: 'cmd-summarize', label: 'Summarize' }Icon CSS
Icon class for visual representation:
{ label: 'Summarize', iconCss: 'e-icons e-collapse-2' }ID (Optional)
Unique identifier for detecting and referencing specific commands:
{
id: 'cmd-summarize',
label: 'Summarize',
prompt: 'Summarize the content'
}Usage in event handlers:
public onCommandSelect = (args: CommandItemSelectEventArgs) => {
// Identify command by ID
if (args.command.id === 'cmd-summarize') {
console.log('Summarize command selected');
// Perform specific action for summarize
} else if (args.command.id === 'cmd-translate') {
console.log('Translate command selected');
// Perform specific action for translate
}
}Benefits:
- Reliable command identification (label text may change with localization)
- Programmatic command triggering
- Better maintainability in large command sets
Tooltip
Hover text describing the command:
{ label: 'Summarize', tooltip: 'Shorten content to key points' }Extended tooltip example:
{
label: 'Translate',
prompt: 'Translate to Spanish',
iconCss: 'e-icons e-translate',
tooltip: 'Translate the selected text to Spanish language',
groupBy: 'Language'
}Best practices:
- Keep tooltips concise but informative
- Explain what the command does, not just repeat the label
- Include keyboard shortcuts if applicable
Group By
Logical grouping for organized popup display:
{ label: 'Summarize', groupBy: 'Improve content' }Commands with same groupBy value appear under a group header.
Multiple groups example:
public commandSetting: CommandSettingsModel = {
commands: [
{ label: 'Summarize', groupBy: 'Content Improvement', tooltip: 'Create summary' },
{ label: 'Expand', groupBy: 'Content Improvement', tooltip: 'Add details' },
{ label: 'Spanish', groupBy: 'Translation', tooltip: 'Translate to Spanish' },
{ label: 'French', groupBy: 'Translation', tooltip: 'Translate to French' },
{ label: 'Professional', groupBy: 'Tone', tooltip: 'Make it formal' },
{ label: 'Casual', groupBy: 'Tone', tooltip: 'Make it friendly' }
]
}Disabled
Disable command selection based on conditions:
{ label: 'Shorten', disabled: true }Conditional disabling example:
import { Component } from '@angular/core';
import { CommandSettingsModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public selectedText: string = '';
public userPlan: string = 'free'; // 'free' or 'premium'
public commandSetting: CommandSettingsModel = {
commands: [
{
id: 'cmd-summarize',
label: 'Summarize',
prompt: 'Summarize the content',
disabled: false, // Always available
iconCss: 'e-icons e-collapse-2',
groupBy: 'Basic'
},
{
id: 'cmd-translate',
label: 'Advanced Translation',
prompt: 'Translate with context',
disabled: this.userPlan === 'free', // Only for premium users
iconCss: 'e-icons e-translate',
groupBy: 'Premium Features',
tooltip: 'Premium feature'
},
{
id: 'cmd-expand',
label: 'Expand Content',
prompt: 'Add more details',
disabled: this.selectedText.length === 0, // Requires selection
iconCss: 'e-icons e-expand',
groupBy: 'Basic'
}
]
};
// Update disabled state dynamically
public updateCommandStates(): void {
this.commandSetting.commands.forEach(cmd => {
if (cmd.id === 'cmd-expand') {
cmd.disabled = this.selectedText.length === 0;
}
if (cmd.id === 'cmd-translate') {
cmd.disabled = this.userPlan === 'free';
}
});
}
}Use cases for disabled commands:
- Feature gating based on user subscription
- Context-dependent availability (text selected, document type, etc.)
- Temporary unavailability (service down, loading state)
- Permission-based access control
Response Item Properties
Response items are action buttons displayed after the AI generates a response. They use the ResponseItemModel interface to define their properties.
ResponseItemModel Interface
The ResponseItemModel interface defines the structure for response action items:
interface ResponseItemModel {
label?: string; // Display text for the action
iconCss?: string; // CSS class for icon
tooltip?: string; // Hover tooltip text
groupBy?: string; // Group name for organization
disabled?: boolean; // Whether the item is disabled
id?: string; // Unique identifier
}Label
Action text shown to user:
{ label: 'Copy' }
{ label: 'Accept' }
{ label: 'Regenerate' }Best practices:
- Use action verbs (Copy, Accept, Reject, Share)
- Keep labels short (1-2 words)
- Be clear about the action's effect
Icon CSS
Icon for visual identification:
{ label: 'Copy', iconCss: 'e-icons e-copy' }
{ label: 'Accept', iconCss: 'e-icons e-check' }
{ label: 'Regenerate', iconCss: 'e-icons e-refresh' }Common icons for response actions:
e-icons e-check- Accept/Approvee-icons e-close- Reject/Discarde-icons e-copy- Copy to clipboarde-icons e-refresh- Regenerate/Retrye-icons e-share- Share responsee-icons e-edit- Edit responsee-icons e-save- Save response
ID (Optional)
Unique identifier for detecting specific response actions:
{
id: 'action-accept',
label: 'Accept',
iconCss: 'e-icons e-check'
}Usage:
public onResponseSelect = (args: ResponseItemSelectEventArgs) => {
switch (args.command.id) {
case 'action-accept':
this.acceptResponse();
break;
case 'action-copy':
this.copyToClipboard();
break;
case 'action-regenerate':
this.regenerateResponse();
break;
}
}Tooltip
Hover text for response action:
{ label: 'Copy', tooltip: 'Copy response to clipboard' }
{ label: 'Accept', tooltip: 'Insert this response into the document' }
{ label: 'Regenerate', tooltip: 'Generate a new response' }Group By
Group related response actions:
{ label: 'Copy', groupBy: 'Share' }
{ label: 'Email', groupBy: 'Share' }
{ label: 'Accept', groupBy: 'Actions' }
{ label: 'Reject', groupBy: 'Actions' }Organized response items example:
public responseSetting: ResponseSettingsModel = {
items: [
// Primary actions
{ label: 'Accept', iconCss: 'e-icons e-check', groupBy: 'Primary', tooltip: 'Use this response' },
{ label: 'Reject', iconCss: 'e-icons e-close', groupBy: 'Primary', tooltip: 'Discard this response' },
// Secondary actions
{ label: 'Copy', iconCss: 'e-icons e-copy', groupBy: 'Share', tooltip: 'Copy to clipboard' },
{ label: 'Email', iconCss: 'e-icons e-mail', groupBy: 'Share', tooltip: 'Send via email' },
// Utility actions
{ label: 'Regenerate', iconCss: 'e-icons e-refresh', groupBy: 'Utility', tooltip: 'Try again' },
{ label: 'Edit', iconCss: 'e-icons e-edit', groupBy: 'Utility', tooltip: 'Modify response' }
],
itemSelect: this.onResponseSelect
};Disabled
Prevent selection of response action:
{ label: 'Regenerate', disabled: true }Conditional disabling:
export class AppComponent {
public isRegenerating: boolean = false;
public copiedToClipboard: boolean = false;
public responseSetting: ResponseSettingsModel = {
items: [
{
label: 'Regenerate',
iconCss: 'e-icons e-refresh',
disabled: this.isRegenerating, // Disable while regenerating
tooltip: 'Generate alternative response'
},
{
label: 'Copy',
iconCss: 'e-icons e-copy',
disabled: false, // Always enabled
tooltip: this.copiedToClipboard ? 'Copied!' : 'Copy to clipboard'
}
],
itemSelect: this.onResponseSelect
};
public onResponseSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Regenerate' && !this.isRegenerating) {
this.isRegenerating = true;
// Update disabled state
this.updateResponseItems();
// Regenerate logic
setTimeout(() => {
this.isRegenerating = false;
this.updateResponseItems();
}, 2000);
}
}
private updateResponseItems(): void {
if (this.responseSetting.items) {
this.responseSetting.items.forEach(item => {
if (item.label === 'Regenerate') {
item.disabled = this.isRegenerating;
}
});
}
}
}Complete ResponseItemModel Example
import { ResponseSettingsModel, ResponseItemSelectEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public responseSetting: ResponseSettingsModel = {
items: [
{
id: 'resp-accept',
label: 'Accept',
iconCss: 'e-icons e-check',
tooltip: 'Insert this response',
groupBy: 'Primary Actions',
disabled: false
},
{
id: 'resp-discard',
label: 'Discard',
iconCss: 'e-icons e-close',
tooltip: 'Reject this response',
groupBy: 'Primary Actions',
disabled: false
},
{
id: 'resp-copy',
label: 'Copy',
iconCss: 'e-icons e-copy',
tooltip: 'Copy to clipboard',
groupBy: 'Secondary Actions',
disabled: false
},
{
id: 'resp-regenerate',
label: 'Regenerate',
iconCss: 'e-icons e-refresh',
tooltip: 'Generate new response',
groupBy: 'Secondary Actions',
disabled: false
},
{
id: 'resp-edit',
label: 'Edit',
iconCss: 'e-icons e-edit',
tooltip: 'Modify before accepting',
groupBy: 'Advanced',
disabled: false
}
],
itemSelect: this.handleResponseItemSelect
};
public handleResponseItemSelect = (args: ResponseItemSelectEventArgs) => {
const itemId = args.command.id;
const response = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response;
switch (itemId) {
case 'resp-accept':
this.insertResponse(response);
this.inlineAssistComponent.hidePopup();
break;
case 'resp-discard':
this.inlineAssistComponent.hidePopup();
break;
case 'resp-copy':
navigator.clipboard.writeText(response);
this.showToast('Copied to clipboard!');
break;
case 'resp-regenerate':
const lastPrompt = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].prompt;
this.inlineAssistComponent.executePrompt(lastPrompt);
break;
case 'resp-edit':
this.openEditor(response);
break;
}
};
private insertResponse(response: string): void {
const editable = document.getElementById('editableText') as HTMLElement;
if (editable) {
editable.innerHTML = response;
}
}
private showToast(message: string): void {
console.log(message);
// Implement your toast notification
}
private openEditor(response: string): void {
// Open a modal or inline editor with the response
console.log('Opening editor with:', response);
}
}Event Handling
Command Item Select Event
Triggered when user selects a command from popup:
import { CommandItemSelectEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
public onCommandSelect = (args: CommandItemSelectEventArgs) => {
console.log('Selected command:', args.command.label);
console.log('Prompt:', args.command.prompt);
// Perform custom action based on selected command
if (args.command.id === 'cmd-summarize') {
// Handle summarization
}
}
public commandSetting: CommandSettingsModel = {
commands: [...],
itemSelect: this.onCommandSelect
}Response Item Select Event
Triggered when user selects a response action:
import { ResponseItemSelectEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
public onResponseSelect = (args: ResponseItemSelectEventArgs) => {
console.log('Selected action:', args.command.label);
if (args.command.label === 'Accept') {
// Apply response
this.applyResponse();
} else if (args.command.label === 'Copy') {
// Copy response
const response = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response;
navigator.clipboard.writeText(response);
}
}
public responseSetting: ResponseSettingsModel = {
items: [...],
itemSelect: this.onResponseSelect
}Complete Example
import { ViewChild, Component } from '@angular/core';
import {
InlineAIAssistModule,
InlineAIAssistComponent,
CommandSettingsModel,
ResponseSettingsModel,
CommandItemSelectEventArgs,
ResponseItemSelectEventArgs,
InlinePromptRequestEventArgs
} from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container" style="height: 350px; width: 650px;">
<button id="summarizeBtn" class="e-btn e-primary" (click)="onClick()">
Open Commands
</button>
<div id="editableText" contenteditable="true">
<p>Sample content for AI processing</p>
</div>
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#summarizeBtn'"
[commandSettings]="commandSettings"
[responseSettings]="responseSettings"
popupWidth="500px"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
// Command settings with grouped commands
public commandSettings: CommandSettingsModel = {
commands: [
{
label: 'Summarize',
prompt: 'Summarize the content',
iconCss: 'e-icons e-collapse-2',
groupBy: 'Improve content',
tooltip: 'Create a concise summary'
},
{
label: 'Shorten',
prompt: 'Shorten the content',
iconCss: 'e-icons e-shorten',
groupBy: 'Improve content',
tooltip: 'Make it shorter'
},
{
label: 'Expand',
prompt: 'Expand the content with more details',
iconCss: 'e-icons e-expand',
groupBy: 'Improve content',
tooltip: 'Add more information'
},
{
label: 'Translate to Spanish',
prompt: 'Translate to Spanish',
iconCss: 'e-icons e-translate',
groupBy: 'Translate',
tooltip: 'Spanish translation'
},
{
label: 'Make Professional',
prompt: 'Rewrite in professional tone',
iconCss: 'e-icons e-elaborate',
groupBy: 'Tone',
tooltip: 'Professional wording'
}
],
popupWidth: '350px',
popupHeight: '300px',
itemSelect: this.onCommandSelect
};
// Response settings with custom actions
public responseSettings: ResponseSettingsModel = {
items: [
{
label: 'Regenerate',
iconCss: 'e-icons e-refresh',
tooltip: 'Generate alternative response',
groupBy: 'Actions'
},
{
label: 'Copy',
iconCss: 'e-icons e-copy',
tooltip: 'Copy to clipboard',
groupBy: 'Actions'
},
{
label: 'Share',
iconCss: 'e-icons e-share',
tooltip: 'Share response',
groupBy: 'Actions'
}
],
itemSelect: this.onResponseSelect
};
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onCommandSelect = (args: CommandItemSelectEventArgs) => {
console.log('Command selected:', args.command.label);
// Additional logic for specific commands
}
public onResponseSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
const editable = document.getElementById('editableText') as HTMLElement;
if (editable) {
editable.innerHTML = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response;
}
this.inlineAssistComponent.hidePopup();
} else if (args.command.label === 'Copy') {
const response = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response;
navigator.clipboard.writeText(response);
alert('Response copied to clipboard!');
}
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
let response = 'AI-generated response based on the selected command.';
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
}Best Practices
1. Group related commands - Use groupBy to organize similar operations 2. Add descriptive icons - Help users quickly identify commands 3. Provide tooltips - Explain what each command does 4. Handle errors - Catch command execution failures gracefully 5. Disable unavailable commands - Use disabled for context-specific actions 6. Support undo - Allow users to reject and try different commands
Core Configuration of Inline AI Assist
Table of Contents
- Prompt Configuration
- Response Display Modes
- Popup Dimensions
- Placeholder and Z-Index
- CSS Customization
- Prompt-Response Collection
- Streaming Responses
- State Persistence
Prompt Configuration
Setting Prompt Text
Use the prompt property to define the default prompt text for the component:
export class AppComponent {
public prompt: string = "What are the benefits of Inline AI Assist?";
}This sets an initial prompt that users can modify before submitting.
Response Display Modes
Popup Mode (Default)
Displays responses in a floating popup window. Best for review-based workflows where users need to accept or reject suggestions:
export class AppComponent {
public responseMode: string = 'Popup';
}Characteristics:
- Response shown in separate popup
- Accept/Reject buttons visible
- User must explicitly accept to apply
- Good for critical content changes
Inline Mode
Updates content directly in-place without a popup. Best for seamless editing experiences:
export class AppComponent {
public responseMode: string = 'Inline';
}Characteristics:
- Response applied directly to target element
- No separate popup shown
- Faster workflow for trusted operations
- Better for real-time suggestions
Switching Modes
export class AppComponent {
public responseMode: string = 'Popup';
onModeChange(event: Event): void {
const selectElement = event.target as HTMLSelectElement;
this.responseMode = selectElement.value;
this.inlineAssistComponent.responseMode = selectElement.value;
this.inlineAssistComponent.showPopup();
}
}Popup Dimensions
Setting Popup Width
Control popup width using popupWidth property (accepts CSS values or numbers in pixels):
// Fixed width in pixels
[popupWidth]="'500px'"
// CSS value
[popupWidth]="'50%'"
// Number (treated as pixels)
[popupWidth]="500"Setting Popup Height
Control popup height using popupHeight property:
// Fixed height
[popupHeight]="'350px'"
// Auto height (default)
[popupHeight]="'auto'"
// Screen percentage
[popupHeight]="'80vh'"Setting Z-Index
Control stacking order of the popup with zIndex property:
// Default z-index is 1000
[zIndex]="4000" // Higher values appear on topPlaceholder and Z-Index
Setting Placeholder Text
Customize the prompt textarea placeholder:
export class AppComponent {
public placeholder: string = 'Type your custom prompt here...';
}Default placeholder is "Ask or generate AI content.."
Z-Index Management
export class AppComponent {
public zIndex: number = 4000;
}Use higher z-index values when the component appears over other overlays.
CSS Customization
Using CSS Class
Add custom CSS classes to the component for styling:
export class AppComponent {
public cssClass: string = 'custom-assist';
}
Custom CSS Example
/* Custom styling for Inline AI Assist */
.custom-assist {
border: 2px solid #2196f3;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.custom-assist .e-toolbar {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 8px 8px 0 0;
}
.custom-assist .e-input {
font-family: 'Courier New', monospace;
font-size: 14px;
}
/* Theme override */
.custom-assist.e-btn {
background-color: #007bff;
}
.custom-assist.e-btn:hover {
background-color: #0056b3;
}Complete Configuration Example
import { ViewChild, Component } from '@angular/core';
import { InlineAIAssistModule, InlineAIAssistComponent, ResponseSettingsModel, ResponseItemSelectEventArgs, InlinePromptRequestEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container" style="height: 350px; width: 650px;">
<button id="summarizeBtn" class="e-btn e-primary" style="margin-bottom: 10px;" (click)="onClick()">
Content Summarize
</button>
<div id="editableText" contenteditable="true">
<p>Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity.</p>
</div>
<ejs-inlineaiassist
id="defaultInlineAssist"
#inlineAssistComponent
[relateTo]="'#summarizeBtn'"
[cssClass]="cssClass"
[popupWidth]="popupWidth"
[popupHeight]="popupHeight"
[placeholder]="placeholder"
[zIndex]="zIndex"
[responseMode]="responseMode"
[responseSettings]="responseSetting"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
// CSS Class for styling
public cssClass: string = 'custom-assist';
// Popup dimensions
public popupWidth: string = '650px';
public popupHeight: string = '350px';
// Placeholder text
public placeholder: string = 'Type your prompt here...';
// Z-index for stacking
public zIndex: number = 4000;
// Response mode
public responseMode: string = 'Popup';
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
const editable = document.getElementById('editableText') as HTMLElement | null;
if (editable) {
editable.innerHTML = '<p>' +
this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response + '</p>';
}
this.inlineAssistComponent.hidePopup();
} else if (args.command.label === 'Discard') {
this.inlineAssistComponent.hidePopup();
}
}
public responseSetting: ResponseSettingsModel = {
itemSelect: this.itemSelect
}
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
let defaultResponse = 'For real-time prompt processing, connect to your preferred AI service.';
this.inlineAssistComponent.addResponse(defaultResponse);
}, 1000);
};
}Prompt-Response Collection
Managing Prompt History
Access and manage the collection of prompts and responses:
// Get all prompts and responses
const allPrompts = this.inlineAssistComponent.prompts;
// Get last prompt
const lastPrompt = allPrompts[allPrompts.length - 1];
console.log('Prompt:', lastPrompt.prompt);
console.log('Response:', lastPrompt.response);
// Iterate through history
allPrompts.forEach((item: any, index: number) => {
console.log(`[${index}] Q: ${item.prompt}`);
console.log(`[${index}] A: ${item.response}`);
});Pre-loading Prompts
Initialize component with predefined prompt-response pairs:
import { PromptResponseModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public prompts: PromptResponseModel[] = [
{
prompt: "What is AI?",
response: `<div>AI stands for Artificial Intelligence, enabling machines to mimic human intelligence
for tasks such as learning, problem-solving, and decision-making.</div>`
},
{
prompt: "Explain machine learning",
response: `<div>Machine learning is a subset of AI where systems learn and improve from experience
without being explicitly programmed for specific tasks.</div>`
}
];
}Using Pre-loaded Prompts
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
// Search for matching prompt in collection
let foundPrompt = this.prompts.find((promptObj: any) =>
promptObj.prompt === args.prompt
);
let response = foundPrompt
? foundPrompt.response
: 'No predefined response found. Connect to AI service.';
this.inlineAssistComponent.addResponse(response);
}, 1000);
};Streaming Responses
Enable Streaming
Use the enableStreaming property to enable real-time streaming of AI responses (similar to ChatGPT). When enabled, responses are progressively displayed as they arrive:
Type: boolean Default: false
export class AppComponent {
public enableStreaming: boolean = true;
}Characteristics:
- Response text appears progressively in real-time
- Provides better user experience for long responses
- Requires AI service support for streaming
- User sees content as it's being generated
Streaming Implementation Example
import { ViewChild, Component } from '@angular/core';
import { InlineAIAssistModule, InlineAIAssistComponent, InlinePromptRequestEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container">
<button id="aiBtn" class="e-btn e-primary" (click)="onClick()">
AI Assist with Streaming
</button>
<div id="editableText" contenteditable="true">
<p>Type your content here...</p>
</div>
<ejs-inlineaiassist
id="streamAssist"
#inlineAssistComponent
[relateTo]="'#aiBtn'"
[enableStreaming]="true"
popupWidth="500px"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
// Simulate streaming response from AI service
const fullResponse = 'This is a streaming response that appears progressively. ' +
'Each chunk of text is added in real-time, creating a smooth user experience. ' +
'This mimics services like ChatGPT where responses stream in character by character.';
let index = 0;
const chunkSize = 10; // Characters per chunk
const streamInterval = setInterval(() => {
if (index < fullResponse.length) {
const chunk = fullResponse.substring(0, index + chunkSize);
// Pass false to indicate this is not the final update
this.inlineAssistComponent.addResponse(chunk, false);
index += chunkSize;
} else {
// Send final complete response with true flag
this.inlineAssistComponent.addResponse(fullResponse, true);
clearInterval(streamInterval);
}
}, 50); // 50ms between chunks for smooth streaming
};
}Streaming with Real AI Service (OpenAI Example)
import { HttpClient } from '@angular/common/http';
export class AppComponent {
constructor(private http: HttpClient) {}
public onPromptRequest = async (args: InlinePromptRequestEventArgs) => {
try {
// Example using OpenAI streaming API
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${YOUR_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: args.prompt }],
stream: true // Enable streaming from OpenAI
})
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let accumulatedResponse = '';
while (true) {
const { done, value } = await reader!.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n').filter(line => line.trim() !== '');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.substring(6);
if (data === '[DONE]') break;
try {
const parsed = JSON.parse(data);
const content = parsed.choices[0]?.delta?.content || '';
if (content) {
accumulatedResponse += content;
// Update with accumulated response, not final yet
this.inlineAssistComponent.addResponse(accumulatedResponse, false);
}
} catch (e) {
// Skip parsing errors
}
}
}
}
// Mark as final response
this.inlineAssistComponent.addResponse(accumulatedResponse, true);
} catch (error) {
console.error('Streaming error:', error);
this.inlineAssistComponent.addResponse('Error occurred during streaming', true);
}
};
}State Persistence
Enable Persistence
Use the enablePersistence property to maintain component state across page reloads. When enabled, the conversation history and configuration are preserved in browser localStorage:
Type: boolean Default: false
export class AppComponent {
public enablePersistence: boolean = true;
}Important: The component must have a unique id attribute for persistence to work correctly.
Persistence Example
import { Component } from '@angular/core';
import { InlineAIAssistModule, InlinePromptRequestEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div class="container">
<button id="aiBtn" class="e-btn e-primary" (click)="onClick()">
Open AI Assist
</button>
<ejs-inlineaiassist
id="persistentAssist"
[relateTo]="'#aiBtn'"
[enablePersistence]="true"
popupWidth="500px"
placeholder="Your conversation is saved..."
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
<div class="info-box">
<p><strong>State Persistence Enabled</strong></p>
<p>Your conversation history will be preserved when you refresh this page.</p>
<p>Try asking a question, then reload the page - your history remains!</p>
</div>
</div>
`,
styles: [`
.container { padding: 20px; }
.info-box {
margin-top: 20px;
padding: 15px;
background: #e3f2fd;
border-left: 4px solid #2196f3;
}
`]
})
export class AppComponent {
onClick(): void {
// Component state is automatically restored from localStorage
// No additional code needed
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
let response = 'Response for: ' + args.prompt;
// This response will be persisted automatically
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
}Features Persisted
When enablePersistence is set to true, the following are automatically saved:
- Conversation history - All prompts and responses
- Popup dimensions - Width and height settings
- Current prompt text - Unsent prompt in textarea
- Response mode - Popup or Inline mode
- Custom properties - Any user-configured values
Storage Details
Storage Location: Browser's localStorage Storage Key: Component's id attribute value Storage Format: JSON serialized component state
Clearing Persisted State
// Clear state for specific component
localStorage.removeItem('persistentAssist'); // Use component's id
// Clear all Syncfusion component state
Object.keys(localStorage).forEach(key => {
if (key.startsWith('ejs-')) {
localStorage.removeItem(key);
}
});Common Configuration Patterns
Minimal Setup
<ejs-inlineaiassist id="assist" [relateTo]="'#button'"></ejs-inlineaiassist>Full Configuration
<ejs-inlineaiassist
id="assist"
[relateTo]="'#button'"
[responseMode]="'Popup'"
[popupWidth]="'600px'"
[popupHeight]="'400px'"
[placeholder]="'Enter your prompt...'"
[cssClass]="'custom-class'"
[zIndex]="5000"
[enableStreaming]="true"
[enablePersistence]="true"
[responseSettings]="responseSettings"
[commandSettings]="commandSettings"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>Events and Methods
Table of Contents
- Lifecycle Events
- Popup Events
- Prompt Request Event
- Public Methods
- Method Usage Examples
- Complete Event Handling Example
Lifecycle Events
created Event
Triggered when the component rendering is completed. Use this to initialize component state or set up references.
import { Component, ViewChild } from '@angular/core';
import { InlineAIAssistComponent, InlineAIAssistModule } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
template: `
<ejs-inlineaiassist id="assist" (created)="onCreated()"></ejs-inlineaiassist>
`
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public onCreated = () => {
console.log('Component created and initialized');
// Initialize component properties
// Load default prompts
// Set up event listeners
};
}Popup Events
open Event
Triggered when the popup opens. Useful for logging, analytics, or updating UI.
import { OpenEventArgs } from '@syncfusion/ej2-popups';
public onOpen = (args: OpenEventArgs) => {
console.log('Popup opened');
console.log('Event args:', args);
// Track analytics
// Update related UI
// Focus on input
};
close Event
Triggered when the popup closes. Handle cleanup or save state.
import { CloseEventArgs } from '@syncfusion/ej2-popups';
public onClose = (args: CloseEventArgs) => {
console.log('Popup closed');
};
Prompt Request Event
promptRequest Event
Triggered when user submits a prompt. This is where you connect to AI services.
import { InlinePromptRequestEventArgs } from '@syncfusion/ej2-angular-interactive-chat';
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
console.log('Prompt submitted:', args.prompt);
// Step 1: Get the prompt text
const userPrompt = args.prompt;
// Step 2: Call AI service
// Step 3: Get response
// Step 4: Add response using addResponse method
setTimeout(() => {
let response = 'AI-generated response for: ' + userPrompt;
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
Integrating with AI Services
import { HttpClient } from '@angular/common/http';
export class AppComponent {
constructor(private http: HttpClient) {}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
// Show loading state
this.isLoading = true;
// Call OpenAI or your AI service
this.http.post('/api/ai/generate', { prompt: args.prompt })
.subscribe({
next: (response: any) => {
// Add response to component
this.inlineAssistComponent.addResponse(response.text);
this.isLoading = false;
},
error: (error) => {
// Handle error
this.inlineAssistComponent.addResponse('Error processing request');
this.isLoading = false;
}
});
};
}Public Methods
addResponse Method
Adds a response to the component and displays it based on response mode.
// Syntax
addResponse(response: string): void
// Example
this.inlineAssistComponent.addResponse('This is the AI-generated response');
// With HTML content
const htmlResponse = `<div style="color: blue;">
<h4>Summary</h4>
<p>Key points go here</p>
</div>`;
this.inlineAssistComponent.addResponse(htmlResponse);executePrompt Method
Executes a prompt programmatically and triggers the promptRequest event.
// Syntax
executePrompt(prompt: string): void
// Example - Execute a specific prompt
this.inlineAssistComponent.executePrompt('Summarize the content');
// Example - Execute user-provided prompt
onCustomButtonClick(promptText: string): void {
this.inlineAssistComponent.executePrompt(promptText);
}showPopup Method
Displays the Inline AI Assist popup.
// Syntax
showPopup(x?: number, y?: number): void
// Example - Show at default position
this.inlineAssistComponent.showPopup();
// Example - Show at specific coordinates
const x = 100;
const y = 200;
this.inlineAssistComponent.showPopup(x, y);
// Example - Show popup on button click
onClick(): void {
this.inlineAssistComponent.showPopup();
}hidePopup Method
Closes/hides the Inline AI Assist popup.
// Syntax
hidePopup(): void
// Example - Hide popup
this.inlineAssistComponent.hidePopup();
// Example - Hide after accepting response
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
// Apply response
this.applyResponse();
// Hide popup
this.inlineAssistComponent.hidePopup();
}
}showCommandPopup Method
Displays the command selection popup.
// Syntax
showCommandPopup(): void
// Example
onClick(): void {
this.inlineAssistComponent.showPopup();
this.inlineAssistComponent.showCommandPopup();
}hideCommandPopup Method
Closes the command selection popup.
// Syntax
hideCommandPopup(): void
// Example
onHideCommands(): void {
this.inlineAssistComponent.hideCommandPopup();
}Method Usage Examples
Example 1: Dynamic Prompt Execution
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
// Array of predefined prompts
public quickPrompts = [
{ id: 1, text: 'Summarize content', label: 'Summarize' },
{ id: 2, text: 'Make it professional', label: 'Professional' },
{ id: 3, text: 'Translate to Spanish', label: 'Spanish' }
];
public executeQuickPrompt(promptText: string): void {
// Show popup
this.inlineAssistComponent.showPopup();
// Execute prompt
setTimeout(() => {
this.inlineAssistComponent.executePrompt(promptText);
}, 200);
}
}Example 2: Response History Management
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public getPromptHistory(): any[] {
return this.inlineAssistComponent.prompts;
}
public getLastResponse(): string {
const prompts = this.inlineAssistComponent.prompts;
if (prompts && prompts.length > 0) {
return prompts[prompts.length - 1].response;
}
return '';
}
public exportHistory(): string {
const history = this.getPromptHistory();
return JSON.stringify(history, null, 2);
}
public clearHistory(): void {
// Note: Direct clearing may not be available
// You may need to re-initialize component
this.inlineAssistComponent.dataBind();
}
}Example 3: Conditional Popup Display
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public userRole: string = 'user'; // user, admin, premium
public showPopupIfAllowed(): void {
// Check user permissions
if (this.userRole === 'user') {
alert('Feature available for premium users');
return;
}
// Show popup if allowed
this.inlineAssistComponent.showPopup();
}
public executeIfQuotaAvailable(prompt: string): void {
if (this.getUserTokens() <= 0) {
alert('Quota exceeded');
return;
}
// Execute prompt
this.inlineAssistComponent.executePrompt(prompt);
}
private getUserTokens(): number {
// Get from service/store
return 100;
}
}Complete Event Handling Example
import { ViewChild, Component, OnInit } from '@angular/core';
import {
InlineAIAssistModule,
InlineAIAssistComponent,
InlinePromptRequestEventArgs,
ResponseSettingsModel,
ResponseItemSelectEventArgs
} from '@syncfusion/ej2-angular-interactive-chat';
import { OpenEventArgs, CloseEventArgs } from '@syncfusion/ej2-popups';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div class="container">
<div class="info-panel">
<p>Status: {{ status }}</p>
<p>Prompts Count: {{ promptCount }}</p>
<button (click)="onShowStatistics()" class="e-btn">Show Stats</button>
</div>
<button id="triggerBtn" class="e-btn e-primary" (click)="onClick()">
Open AI Assist
</button>
<div id="editableText" contenteditable="true">
<p>Content here...</p>
</div>
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#triggerBtn'"
[responseSettings]="responseSetting"
popupWidth="500px"
(created)="onCreated()"
(open)="onOpen($event)"
(close)="onClose($event)"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`
.container { padding: 20px; }
.info-panel { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; }
#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }
`]
})
export class AppComponent implements OnInit {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public status: string = 'Ready';
public promptCount: number = 0;
private eventLog: any[] = [];
ngOnInit(): void {
// Initialize
}
public responseSetting: ResponseSettingsModel = {
itemSelect: this.itemSelect
}
public onCreated = () => {
this.status = 'Component initialized';
console.log('Component created');
this.logEvent('created');
};
public onOpen = (args: OpenEventArgs) => {
this.status = 'Popup opened';
console.log('Popup opened', args);
this.logEvent('open');
};
public onClose = (args: CloseEventArgs) => {
this.status = 'Popup closed';
console.log('Popup closed', args);
this.logEvent('close');
};
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
this.status = 'Processing prompt...';
this.logEvent('promptRequest', { prompt: args.prompt });
console.log('Prompt requested:', args.prompt);
setTimeout(() => {
let response = 'Response for: ' + args.prompt;
this.inlineAssistComponent.addResponse(response);
this.promptCount = this.inlineAssistComponent.prompts.length;
this.status = 'Response added';
}, 1000);
};
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
const editable = document.getElementById('editableText') as HTMLElement;
if (editable) {
editable.innerHTML = this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response;
}
this.inlineAssistComponent.hidePopup();
this.status = 'Response accepted';
}
}
public onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onShowStatistics(): void {
const stats = {
totalPrompts: this.promptCount,
eventLog: this.eventLog,
history: this.inlineAssistComponent.prompts
};
console.table(stats);
alert(`Total prompts: ${this.promptCount}\nSee console for details`);
}
private logEvent(eventName: string, details?: any): void {
this.eventLog.push({
time: new Date().toLocaleTimeString(),
event: eventName,
details: details
});
}
}Error Handling
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
try {
// Validate prompt
if (!args.prompt || args.prompt.trim() === '') {
throw new Error('Prompt cannot be empty');
}
// Call AI service with error handling
this.callAIService(args.prompt)
.then((response) => {
this.inlineAssistComponent.addResponse(response);
})
.catch((error) => {
console.error('AI service error:', error);
this.inlineAssistComponent.addResponse(
'Error: Unable to process request. Please try again.'
);
});
} catch (error) {
console.error('Event handler error:', error);
this.inlineAssistComponent.addResponse(
'An error occurred. Please check the console for details.'
);
}
};
private callAIService(prompt: string): Promise<string> {
return new Promise((resolve, reject) => {
// Simulate API call
setTimeout(() => {
resolve('AI response here');
}, 1000);
});
}Getting Started with Syncfusion Angular Inline AI Assist
Table of Contents
- Installation
- Angular Environment Setup
- Package Installation
- CSS References
- Basic Implementation
- Configure Position
- Run the Application
Installation
The Inline AI Assist component is distributed as part of the @syncfusion/ej2-angular-interactive-chat package.
Dependencies
The following dependencies are required:
@syncfusion/ej2-angular-interactive-chat
├── @syncfusion/ej2-base
├── @syncfusion/ej2-navigations
├── @syncfusion/ej2-inputs
├── @syncfusion/ej2-buttons
├── @syncfusion/ej2-dropdowns
└── @syncfusion/ej2-popupsAngular Environment Setup
Install Angular CLI
npm install -g @angular/cliCreate Angular Application
ng new my-inline-ai-app
cd my-inline-ai-appPackage Installation
Install the Syncfusion Inline AI Assist package:
npm install @syncfusion/ej2-angular-interactive-chat --saveCSS References
Add the required CSS files to src/styles.css:
@import "../node_modules/@syncfusion/ej2-base/styles/material.css";
@import '../node_modules/@syncfusion/ej2-interactive-chat/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';Basic Implementation
Update app.component.ts
Modify src/app/app.component.ts to add the Inline AI Assist component:
import { Component } from '@angular/core';
import { InlineAIAssistModule } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<ejs-inlineaiassist id='inlineAssist'></ejs-inlineaiassist>
`
})
export class AppComponent { }Full Working Example
Here's a complete example with event handling:
import { ViewChild, Component } from '@angular/core';
import {
InlineAIAssistModule,
InlineAIAssistComponent,
InlinePromptRequestEventArgs,
ResponseSettingsModel,
ResponseItemSelectEventArgs
} from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container" style="height: 350px; width: 650px;">
<button id="summarizeBtn" class="e-btn e-primary" style="margin-bottom: 10px;" (click)="onClick()">
Content Summarize
</button>
<div id="editableText" contenteditable="true">
<p>Inline AI Assist component provides intelligent text processing capabilities that enhance user productivity.
It leverages advanced natural language processing to understand context and deliver precise suggestions.
Users can seamlessly integrate AI-powered features into their applications.</p>
<p>With real-time response streaming and customizable prompts, developers can create interactive experiences.
The component supports multiple response modes including inline editing and popup-based interactions.</p>
</div>
<ejs-inlineaiassist
id="defaultInlineAssist"
#inlineAssistComponent
[relateTo]="'#summarizeBtn'"
[responseSettings]="responseSetting"
popupWidth="500px"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`,
styles: [`
#editableText {
width: 100%;
min-height: 120px;
max-height: 300px;
overflow-y: auto;
font-size: 16px;
padding: 12px;
border-radius: 4px;
border: 1px solid;
}
`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public itemSelect = (args: ResponseItemSelectEventArgs) => {
if (args.command.label === 'Accept') {
const editable = document.getElementById('editableText') as HTMLElement | null;
if (editable) {
editable.innerHTML = '<p>' +
this.inlineAssistComponent.prompts[
this.inlineAssistComponent.prompts.length - 1
].response + '</p>';
}
this.inlineAssistComponent.hidePopup();
} else if (args.command.label === 'Discard') {
this.inlineAssistComponent.hidePopup();
}
}
public responseSetting: ResponseSettingsModel = {
itemSelect: this.itemSelect
}
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onPromptRequest = (args: InlinePromptRequestEventArgs) => {
setTimeout(() => {
let defaultResponse = 'For real-time prompt processing, connect to your preferred AI service, '
+ 'such as OpenAI or Azure Cognitive Services. Ensure you obtain the necessary API credentials '
+ 'to authenticate and enable seamless integration.';
this.inlineAssistComponent.addResponse(defaultResponse);
}, 1000);
};
}Configure Position
Using relateTo Property
The relateTo property positions the Inline AI Assist popup relative to a specific DOM element (CSS selector or HTMLElement):
<ejs-inlineaiassist
id="inlineAssist"
[relateTo]="'#summarizeBtn'"
popupWidth="500px">
</ejs-inlineaiassist>Using target Property
The target property specifies where the component will be appended in the DOM:
<div id="container">
<button id="summarizeBtn" class="e-btn e-primary">Summarize</button>
<div id="editableText" contenteditable="true">Your content here</div>
</div>
<ejs-inlineaiassist
id="inlineAssist"
[target]="'#container'"
[relateTo]="'#summarizeBtn'"
popupWidth="500px">
</ejs-inlineaiassist>Run the Application
Execute the development server:
ng serveThe application will be available at http://localhost:4200/. The Inline AI Assist component will render when the button is clicked and show the popup relative to the target element.
Expected Output
- A button labeled "Content Summarize"
- An editable text area with sample content
- When button clicked, Inline AI Assist popup appears with:
- Prompt textarea with placeholder "Ask or generate AI content.."
- Send button in the inline toolbar
- Response display area
- Accept/Reject action buttons
Next Steps
After basic setup, explore:
- Configure prompt text and placeholder
- Add command settings for preset operations
- Customize response actions and toolbars
- Implement template customization
- Handle events and integrate with AI services
Localization and Styling
Table of Contents
- Localization Overview
- Supported Locales
- Implementing Localization
- Right-to-Left (RTL)
- Custom CSS Styling
- Theme Integration
- Dark Mode
Localization Overview
The Inline AI Assist component supports multiple languages and locales. You can customize all user-facing text including buttons, placeholders, and labels.
Default Localization Strings
The following strings can be customized for each locale:
| Key | Default Text | Purpose |
|---|---|---|
send | Send | Send button label |
stopResponseText | Stop Responding | Stop processing label |
thinkingIndicator | Thinking | Thinking state indicator |
editingIndicator | Editing | Editing state indicator |
Supported Locales
Common locale codes:
en- English (default)de- Germande-DE- German (Germany)es- Spanishes-ES- Spanish (Spain)fr- Frenchfr-FR- French (France)ja- Japanesezh- Chinesezh-CN- Chinese (Simplified)ar- Arabicit- Italianpt- Portugueseru- Russian- And many more...
Implementing Localization
Basic Localization Setup
import { Component, ViewChild } from '@angular/core';
import { InlineAIAssistModule, InlineAIAssistComponent } from '@syncfusion/ej2-angular-interactive-chat';
import { L10n } from '@syncfusion/ej2-base';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<ejs-inlineaiassist
id="assist"
[relateTo]="'#button'"
[locale]="locale">
</ejs-inlineaiassist>
`
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public locale: string = 'en';
ngOnInit(): void {
this.setupLocalization();
}
private setupLocalization(): void {
// Load German localization
L10n.load({
'de': {
'inline-ai-assist': {
'send': 'Senden',
'stopResponseText': 'Antwort stoppen',
'thinkingIndicator': 'Wird verarbeitet',
'editingIndicator': 'Wird bearbeitet'
}
}
});
}
}Setting Locale Property
export class AppComponent {
public locale: string = 'de-DE'; // German (Germany)
// Change locale dynamically
changeLocale(newLocale: string): void {
this.locale = newLocale;
this.inlineAssistComponent.locale = newLocale;
this.inlineAssistComponent.dataBind();
}
}Multiple Language Support
import { L10n } from '@syncfusion/ej2-base';
export class LocalizationService {
public static setupAllLocales(): void {
L10n.load({
'de': {
'inline-ai-assist': {
'send': 'Senden',
'stopResponseText': 'Antwort stoppen'
}
},
'es': {
'inline-ai-assist': {
'send': 'Enviar',
'stopResponseText': 'Detener respuesta'
}
},
'fr': {
'inline-ai-assist': {
'send': 'Envoyer',
'stopResponseText': 'Arrêter la réponse'
}
},
'ja': {
'inline-ai-assist': {
'send': '送信',
'stopResponseText': '応答を停止'
}
},
'zh-CN': {
'inline-ai-assist': {
'send': '发送',
'stopResponseText': '停止响应'
}
}
});
}
}
// In your app component
export class AppComponent {
ngOnInit(): void {
LocalizationService.setupAllLocales();
}
}Right-to-Left (RTL)
Enable RTL
Use the enableRtl property to support right-to-left languages:
export class AppComponent {
public enableRtl: boolean = false;
public setArabic(): void {
this.locale = 'ar';
this.enableRtl = true;
this.inlineAssistComponent.locale = 'ar';
this.inlineAssistComponent.enableRtl = true;
this.inlineAssistComponent.dataBind();
}
}RTL Localization Example
export class AppComponent {
ngOnInit(): void {
// Load Arabic localization with RTL
L10n.load({
'ar': {
'inline-ai-assist': {
'send': 'إرسال',
'stopResponseText': 'إيقاف الاستجابة',
'thinkingIndicator': 'جاري المعالجة',
'editingIndicator': 'جاري التحرير'
}
}
});
this.locale = 'ar';
this.enableRtl = true;
}
}RTL CSS
/* RTL Container */
.e-inline-ai-assist[dir="rtl"] {
direction: rtl;
text-align: right;
}
/* RTL Buttons */
.e-inline-ai-assist[dir="rtl"] .e-btn {
margin-left: 5px;
margin-right: 0;
}
/* RTL Input */
.e-inline-ai-assist[dir="rtl"] input,
.e-inline-ai-assist[dir="rtl"] textarea {
direction: rtl;
text-align: right;
}
/* RTL Icons */
.e-inline-ai-assist[dir="rtl"] .e-icon {
margin-right: 5px;
margin-left: 0;
}Custom CSS Styling
Global CSS Customization
/* Component container */
.e-inline-ai-assist {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #333;
}
/* Popup styling */
.e-inline-ai-assist .e-popup {
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
/* Input area */
.e-inline-ai-assist textarea {
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
font-size: 14px;
line-height: 1.5;
}
.e-inline-ai-assist textarea:focus {
outline: none;
border-color: #2196f3;
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
}
/* Buttons */
.e-inline-ai-assist .e-btn {
border-radius: 4px;
font-weight: 500;
transition: all 0.3s ease;
}
.e-inline-ai-assist .e-btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
/* Response area */
.e-inline-ai-assist .e-response-item {
padding: 12px;
margin: 8px 0;
background: #f5f5f5;
border-radius: 6px;
border-left: 3px solid #2196f3;
}
/* Toolbar */
.e-inline-ai-assist .e-toolbar {
background: #f9f9f9;
border-top: 1px solid #ddd;
padding: 8px;
}Component-Specific CSS Class
export class AppComponent {
public cssClass: string = 'custom-assist-theme';
}/* Custom theme */
.custom-assist-theme {
--primary-color: #007bff;
--border-color: #ddd;
--background-color: #fff;
--text-color: #333;
}
.custom-assist-theme .e-popup {
background: var(--background-color);
border: 1px solid var(--border-color);
}
.custom-assist-theme .e-btn-primary {
background: var(--primary-color);
}Theme Integration
Material Theme
import '@syncfusion/ej2-base/styles/material.css';
import '@syncfusion/ej2-interactive-chat/styles/material.css';
// Component automatically uses Material designFluent Theme
import '@syncfusion/ej2-base/styles/fluent.css';
import '@syncfusion/ej2-interactive-chat/styles/fluent.css';Bootstrap Theme
import '@syncfusion/ej2-base/styles/bootstrap.css';
import '@syncfusion/ej2-interactive-chat/styles/bootstrap.css';Dark Mode
Dark Mode CSS
/* Dark mode styles */
@media (prefers-color-scheme: dark) {
.e-inline-ai-assist {
background: #1e1e1e;
color: #e0e0e0;
}
.e-inline-ai-assist .e-popup {
background: #2d2d2d;
border-color: #444;
}
.e-inline-ai-assist textarea {
background: #3c3c3c;
color: #e0e0e0;
border-color: #555;
}
.e-inline-ai-assist .e-response-item {
background: #2a2a2a;
border-left-color: #64b5f6;
}
.e-inline-ai-assist .e-toolbar {
background: #2d2d2d;
border-color: #444;
}
}Manual Dark Mode Toggle
export class AppComponent {
public isDarkMode: boolean = false;
public toggleDarkMode(): void {
this.isDarkMode = !this.isDarkMode;
if (this.isDarkMode) {
document.body.classList.add('dark-mode');
} else {
document.body.classList.remove('dark-mode');
}
}
}/* Dark mode implementation */
body.dark-mode {
background: #1a1a1a;
color: #e0e0e0;
}
body.dark-mode .e-inline-ai-assist {
background: #2d2d2d;
color: #e0e0e0;
}
body.dark-mode .e-inline-ai-assist textarea {
background: #3c3c3c;
color: #e0e0e0;
border-color: #555;
}Complete Localization Example
import { Component, ViewChild, OnInit } from '@angular/core';
import { InlineAIAssistModule, InlineAIAssistComponent } from '@syncfusion/ej2-angular-interactive-chat';
import { L10n } from '@syncfusion/ej2-base';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div class="settings">
<label>Language:
<select (change)="changeLanguage($event.target.value)" [value]="currentLanguage">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="es">Español</option>
<option value="fr">Français</option>
<option value="ar">العربية</option>
</select>
</label>
<label>
<input type="checkbox" (change)="toggleDarkMode()" [checked]="isDarkMode">
Dark Mode
</label>
</div>
<button id="assistBtn" class="e-btn e-primary" (click)="onClick()">
{{ currentLanguage === 'de' ? 'AI Assistent öffnen' : 'Open AI Assist' }}
</button>
<div id="editableText" contenteditable="true">
<p>Content...</p>
</div>
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#assistBtn'"
[locale]="currentLanguage"
[enableRtl]="currentLanguage === 'ar'"
[cssClass]="isDarkMode ? 'dark-mode' : ''">
</ejs-inlineaiassist>
`,
styles: [`
.settings { margin-bottom: 20px; }
.settings label { margin-right: 20px; }
.settings select { padding: 5px; }
#editableText { width: 100%; min-height: 120px; padding: 12px; border: 1px solid; }
`]
})
export class AppComponent implements OnInit {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public currentLanguage: string = 'en';
public isDarkMode: boolean = false;
ngOnInit(): void {
this.setupLocales();
}
private setupLocales(): void {
L10n.load({
'de': {
'inline-ai-assist': {
'send': 'Senden',
'stopResponseText': 'Antwort stoppen',
'thinkingIndicator': 'Wird verarbeitet',
'editingIndicator': 'Wird bearbeitet'
}
},
'es': {
'inline-ai-assist': {
'send': 'Enviar',
'stopResponseText': 'Detener respuesta'
}
},
'fr': {
'inline-ai-assist': {
'send': 'Envoyer',
'stopResponseText': 'Arrêter la réponse'
}
},
'ar': {
'inline-ai-assist': {
'send': 'إرسال',
'stopResponseText': 'إيقاف الاستجابة'
}
}
});
}
public changeLanguage(lang: string): void {
this.currentLanguage = lang;
this.inlineAssistComponent.locale = lang;
this.inlineAssistComponent.enableRtl = lang === 'ar';
this.inlineAssistComponent.dataBind();
}
public toggleDarkMode(): void {
this.isDarkMode = !this.isDarkMode;
const body = document.body;
if (this.isDarkMode) {
body.classList.add('dark-mode');
} else {
body.classList.remove('dark-mode');
}
}
public onClick(): void {
this.inlineAssistComponent.showPopup();
}
}Templates and Toolbars
Table of Contents
- Editor Template
- Response Template
- Inline Toolbar Configuration
- Toolbar Item Properties
- Toolbar Positioning
- Tab Key Navigation
Editor Template
Overview
The editor template customizes the footer area where users enter prompts. Use this to create custom layouts, add buttons, or modify the input experience.
Type: string | object Default: ''
The editorTemplate property accepts two types of values:
1. String template - HTML markup as a string 2. Object/Function template - Angular template reference or function that returns markup
Template Types Explained
String Template
Direct HTML string for simple customizations:
export class AppComponent {
public editorTemplate: string = `
<div class="custom-editor">
<textarea placeholder="Custom prompt input"></textarea>
<button onclick="submitPrompt()">Send</button>
</div>
`;
}Angular Template Reference (Recommended)
Use Angular ng-template for better integration:
// In template: #editorTemplate
// In component: Access via template referenceBest practice: Use Angular template references for access to component context, data binding, and event handlers.
Basic Editor Template
import { ViewChild, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { InlineAIAssistModule, InlineAIAssistComponent } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [CommonModule, FormsModule, InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#button'"
(promptRequest)="onPromptRequest($event)">
<!-- Custom Editor Template -->
<ng-template #editorTemplate>
<div class="custom-footer">
<textarea
id="promptTextArea"
class="e-input"
rows="2"
placeholder="Enter your prompt here"
[(ngModel)]="promptText">
</textarea>
<button
id="sendPrompt"
class="e-btn e-primary"
(click)="onGenerateClick()">
Generate
</button>
</div>
</ng-template>
</ejs-inlineaiassist>
`,
styles: [`
.custom-footer {
display: flex;
gap: 10px;
padding: 10px;
background-color: transparent;
}
#promptTextArea {
width: 100%;
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
font-family: inherit;
}
#sendPrompt {
padding: 5px 15px;
align-self: flex-end;
white-space: nowrap;
}
`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public promptText: string = '';
onGenerateClick(): void {
if (this.promptText.trim()) {
this.inlineAssistComponent.executePrompt(this.promptText.trim());
this.promptText = '';
}
}
public onPromptRequest = (args: any) => {
setTimeout(() => {
let response = 'Response for: ' + args.prompt;
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
}Advanced Editor Template
<ng-template #editorTemplate>
<div class="advanced-editor">
<div class="editor-toolbar">
<button class="tool-btn" title="Bold"><i class="e-icons e-bold"></i></button>
<button class="tool-btn" title="Italic"><i class="e-icons e-italic"></i></button>
<button class="tool-btn" title="Underline"><i class="e-icons e-underline"></i></button>
<span class="divider"></span>
</div>
<textarea
class="prompt-input"
rows="3"
[(ngModel)]="promptText"
placeholder="Enter prompt...">
</textarea>
<div class="editor-actions">
<button class="e-btn e-outline" (click)="onCancel()">Cancel</button>
<button class="e-btn e-primary" (click)="onGenerateClick()">Generate</button>
</div>
</div>
</ng-template>Response Template
Overview
The response template customizes how AI responses are displayed. Create custom layouts for response items with headers, icons, and styling.
Type: string | object Default: ''
The responseTemplate property accepts two types of values:
1. String template - HTML markup as a string 2. Object/Function template - Angular template reference with access to response data
Template Context
The response template function receives a context object with the following structure:
interface ResponseTemplateContext {
prompt: string; // The user's prompt text
response: string; // The AI-generated response
index?: number; // Index in the prompts array
}Usage in template:
<ng-template #responseTemplate let-data>
<div>
<p>Prompt: {{ data.prompt }}</p>
<p>Response: {{ data.response }}</p>
</div>
</ng-template>Basic Response Template
<ng-template #responseTemplate let-data>
<div class="responseItemContent">
<div class="response-header">
<span class="e-icons e-assistview-icon"></span>
<span>AI Response</span>
</div>
<div class="responseContent" [innerHTML]="data.response"></div>
</div>
</ng-template>Complete Response Template Example
import { ViewChild, Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { InlineAIAssistModule, InlineAIAssistComponent } from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [CommonModule, InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#button'"
[prompts]="promptsData"
(promptRequest)="onPromptRequest($event)">
<!-- Custom Response Template -->
<ng-template #responseTemplate let-data>
<div class="responseItemContent">
<div class="response-header">
<span class="e-icons e-assistview-icon"></span>
Inline AI Assist
</div>
<div class="responseContent" [innerHTML]="data.response"></div>
<div class="response-metadata">
<span class="timestamp">{{ getCurrentTime() }}</span>
</div>
</div>
</ng-template>
</ejs-inlineaiassist>
`,
styles: [`
.responseItemContent {
display: flex;
flex-direction: column;
gap: 10px;
}
.response-header {
font-size: 16px;
font-weight: bold;
display: flex;
align-items: center;
color: #2196f3;
}
.response-header .e-assistview-icon {
margin-right: 10px;
}
.responseContent {
margin-left: 35px;
line-height: 1.6;
color: #333;
}
.response-metadata {
margin-left: 35px;
margin-top: 5px;
font-size: 12px;
color: #999;
}
.e-response-item-template .e-toolbar-items {
margin-left: 35px;
}
`]
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public promptsData = [
{
prompt: "What is AI?",
response: `<div>AI stands for Artificial Intelligence, enabling machines to mimic human intelligence
for tasks such as learning, problem-solving, and decision-making.</div>`
}
];
getCurrentTime(): string {
return new Date().toLocaleTimeString();
}
public onPromptRequest = (args: any) => {
setTimeout(() => {
let response = 'Custom formatted response...';
this.inlineAssistComponent.addResponse(response);
}, 1000);
};
}Inline Toolbar Configuration
Overview
The inline toolbar appears within the prompt input area. Configure it to add custom buttons alongside the default send button.
InlineToolbarSettingsModel Properties
The InlineToolbarSettingsModel interface configures the inline toolbar:
interface InlineToolbarSettingsModel {
items?: ToolbarItemModel[]; // Array of toolbar items
toolbarPosition?: ToolbarPosition | string; // Position of toolbar
itemClick?: EmitType<ToolbarItemClickEventArgs>; // Click event handler
}Toolbar Position Property
Type: ToolbarPosition | string Default: 'Bottom' Allowed values: 'Top' | 'Bottom' | 'Inline'
Control where the toolbar appears relative to the prompt input:
import { InlineToolbarSettingsModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
// Bottom position (default)
public toolbarBottom: InlineToolbarSettingsModel = {
toolbarPosition: 'Bottom',
items: [
{ iconCss: 'e-icons e-send', type: 'Button', align: 'Right' }
]
};
// Top position
public toolbarTop: InlineToolbarSettingsModel = {
toolbarPosition: 'Top',
items: [
{ iconCss: 'e-icons e-send', type: 'Button', align: 'Right' }
]
};
// Inline position (within same line as input)
public toolbarInline: InlineToolbarSettingsModel = {
toolbarPosition: 'Inline',
items: [
{ iconCss: 'e-icons e-send', type: 'Button', align: 'Right' }
]
};
}Toolbar Item Click Event
Type: EmitType<ToolbarItemClickEventArgs>
Handle clicks on toolbar buttons:
import { ToolbarItemClickEventArgs, InlineToolbarSettingsModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
id: 'clear-btn',
iconCss: 'e-icons e-close',
align: 'Right',
type: 'Button',
tooltip: 'Clear'
},
{
id: 'emoji-btn',
iconCss: 'e-icons e-emoji',
align: 'Right',
type: 'Button',
tooltip: 'Insert Emoji'
},
{
id: 'attach-btn',
iconCss: 'e-icons e-attachment',
align: 'Left',
type: 'Button',
tooltip: 'Attach File'
}
],
itemClick: this.onToolbarItemClick
};
public onToolbarItemClick = (args: ToolbarItemClickEventArgs) => {
console.log('Toolbar item clicked:', args.item);
// Access clicked item details
const itemId = args.item.id;
switch (itemId) {
case 'clear-btn':
this.clearPrompt();
break;
case 'emoji-btn':
this.showEmojiPicker();
break;
case 'attach-btn':
this.openFileDialog();
break;
}
};
private clearPrompt(): void {
this.inlineAssistComponent.prompt = '';
console.log('Prompt cleared');
}
private showEmojiPicker(): void {
console.log('Opening emoji picker');
// Implement emoji picker logic
}
private openFileDialog(): void {
console.log('Opening file dialog');
// Implement file attachment logic
}
}Complete Toolbar Configuration Example
import { ViewChild, Component } from '@angular/core';
import {
InlineAIAssistModule,
InlineAIAssistComponent,
InlineToolbarSettingsModel,
ToolbarItemClickEventArgs
} from '@syncfusion/ej2-angular-interactive-chat';
@Component({
imports: [InlineAIAssistModule],
standalone: true,
selector: 'app-root',
template: `
<div id="container">
<button id="aiBtn" class="e-btn e-primary" (click)="onClick()">
Open AI Assist
</button>
<ejs-inlineaiassist
id="assist"
#inlineAssistComponent
[relateTo]="'#aiBtn'"
[inlineToolbarSettings]="inlineToolbarSettings"
popupWidth="600px"
(promptRequest)="onPromptRequest($event)">
</ejs-inlineaiassist>
</div>
`
})
export class AppComponent {
@ViewChild('inlineAssistComponent')
public inlineAssistComponent!: InlineAIAssistComponent;
public inlineToolbarSettings: InlineToolbarSettingsModel = {
toolbarPosition: 'Bottom',
items: [
{
id: 'attach',
iconCss: 'e-icons e-attachment',
align: 'Left',
type: 'Button',
tooltip: 'Attach file'
},
{
id: 'emoji',
iconCss: 'e-icons e-emoji',
align: 'Left',
type: 'Button',
tooltip: 'Insert emoji'
},
{
type: 'Separator',
align: 'Left'
},
{
id: 'clear',
iconCss: 'e-icons e-trash',
align: 'Right',
type: 'Button',
tooltip: 'Clear prompt'
},
{
id: 'voice',
iconCss: 'e-icons e-microphone',
align: 'Right',
type: 'Button',
tooltip: 'Voice input'
}
],
itemClick: this.handleToolbarClick
};
public handleToolbarClick = (args: ToolbarItemClickEventArgs) => {
const itemId = args.item.id;
console.log(`Toolbar button clicked: ${itemId}`);
switch (itemId) {
case 'clear':
this.inlineAssistComponent.prompt = '';
break;
case 'emoji':
this.insertEmoji('😊');
break;
case 'voice':
this.startVoiceInput();
break;
case 'attach':
this.attachFile();
break;
}
};
private insertEmoji(emoji: string): void {
const currentPrompt = this.inlineAssistComponent.prompt || '';
this.inlineAssistComponent.prompt = currentPrompt + emoji;
}
private startVoiceInput(): void {
console.log('Starting voice input...');
// Implement speech-to-text
}
private attachFile(): void {
console.log('Attaching file...');
// Implement file attachment
}
onClick(): void {
this.inlineAssistComponent.showPopup();
}
public onPromptRequest = (args: any) => {
setTimeout(() => {
this.inlineAssistComponent.addResponse('Response generated');
}, 1000);
};
}Basic Inline Toolbar
import { InlineToolbarSettingsModel } from '@syncfusion/ej2-angular-interactive-chat';
export class AppComponent {
public inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
iconCss: 'e-icons e-refresh',
align: 'Right',
type: 'Button'
},
{
type: 'Button',
iconCss: 'e-icons e-maximize-2',
align: 'Right',
tooltip: 'Expand'
}
]
};
}Toolbar Item Properties
ToolbarItemModel Interface
The ToolbarItemModel interface defines toolbar button configuration:
interface ToolbarItemModel {
id?: string; // Unique identifier
type?: string; // 'Button' | 'Separator' | 'Input'
text?: string; // Button label text
iconCss?: string; // Icon CSS class
tooltip?: string; // Hover tooltip
align?: string; // 'Left' | 'Center' | 'Right'
disabled?: boolean; // Whether disabled
visible?: boolean; // Whether visible
cssClass?: string; // Custom CSS class
width?: string | number; // Item width
htmlAttributes?: object; // Custom HTML attributes
}ID
Unique identifier for the toolbar item:
{
id: 'clear-btn',
type: 'Button',
iconCss: 'e-icons e-trash'
}Usage: Essential for identifying items in click event handlers.
Type
Item type: 'Button', 'Separator', or 'Input'
{ type: 'Button' } // Clickable button
{ type: 'Separator' } // Visual divider
{ type: 'Input' } // Input fieldCommon usage:
public toolbarItems = [
{ id: 'btn1', type: 'Button', text: 'Action' },
{ type: 'Separator' }, // Visual divider
{ id: 'btn2', type: 'Button', text: 'Another Action' }
];Text
Button label text:
{ text: 'Clear', type: 'Button' }
{ text: 'Send', type: 'Button', iconCss: 'e-icons e-send' }With icon:
{
id: 'save-btn',
text: 'Save',
iconCss: 'e-icons e-save',
type: 'Button'
}Icon CSS
Icon class for visual display:
{ iconCss: 'e-icons e-refresh' }
{ iconCss: 'e-icons e-send' }
{ iconCss: 'e-icons e-attachment' }Syncfusion icon classes:
e-icons e-send- Send icone-icons e-trash- Delete/Clear icone-icons e-attachment- Attachment icone-icons e-emoji- Emoji icone-icons e-microphone- Voice input icone-icons e-close- Close icone-icons e-refresh- Refresh icon
Tooltip
Hover tooltip:
{ tooltip: 'Clear all prompts' }
{ tooltip: 'Send message (Ctrl+Enter)' }
{ tooltip: 'Attach file' }Best practices:
- Include keyboard shortcuts when applicable
- Be descriptive but concise
- Explain the action, not just repeat the label
Alignment
Position: 'Left', 'Center', 'Right'
{ align: 'Right' } // Positioned on the right
{ align: 'Left' } // Positioned on the left
{ align: 'Center' } // CenteredLayout example:
public toolbarItems = [
{ id: 'attach', iconCss: 'e-icons e-attachment', align: 'Left' },
{ id: 'emoji', iconCss: 'e-icons e-emoji', align: 'Left' },
{ id: 'send', iconCss: 'e-icons e-send', align: 'Right' },
{ id: 'clear', iconCss: 'e-icons e-trash', align: 'Right' }
];Disabled
Disable the item:
{ disabled: true }
{ disabled: false }Conditional disabling:
export class AppComponent {
public promptText: string = '';
public getToolbarItems() {
return [
{
id: 'send',
iconCss: 'e-icons e-send',
disabled: this.promptText.trim().length === 0, // Disable if empty
tooltip: 'Send message'
},
{
id: 'clear',
iconCss: 'e-icons e-trash',
disabled: this.promptText.length === 0, // Disable if nothing to clear
tooltip: 'Clear prompt'
}
];
}
}Visible
Show/hide the item:
{ visible: false } // Hidden
{ visible: true } // Visible (default)Conditional visibility:
export class AppComponent {
public isVoiceSupported: boolean = 'webkitSpeechRecognition' in window;
public isPremiumUser: boolean = true;
public toolbarItems = [
{
id: 'voice',
iconCss: 'e-icons e-microphone',
visible: this.isVoiceSupported, // Only show if browser supports it
tooltip: 'Voice input'
},
{
id: 'premium-feature',
iconCss: 'e-icons e-star',
visible: this.isPremiumUser, // Only for premium users
tooltip: 'Premium feature'
}
];
}CSS Class
Custom styling:
{ cssClass: 'custom-btn' }
{ cssClass: 'primary-action' }CSS example:
.custom-btn {
background-color: #2196f3;
color: white;
border-radius: 4px;
padding: 8px 16px;
}
.primary-action {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}Width
Item width in pixels or CSS units:
{ width: 100 } // 100px
{ width: '80px' } // 80px
{ width: '10%' } // PercentageHTML Attributes
Custom HTML attributes:
{
id: 'custom-btn',
type: 'Button',
htmlAttributes: {
'data-action': 'submit',
'aria-label': 'Submit prompt',
'class': 'custom-button-class'
}
}Complete Toolbar Example
public inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
// Left aligned separator
type: 'Separator',
align: 'Left'
},
{
// Refresh button (right)
iconCss: 'e-icons e-refresh',
align: 'Right',
type: 'Button',
tooltip: 'Refresh',
cssClass: 'toolbar-refresh'
},
{
// User button (right)
type: 'Button',
iconCss: 'e-icons e-user',
align: 'Right',
cssClass: 'toolbar-user',
tooltip: 'User profile'
},
{
// Maximize button (right)
type: 'Button',
iconCss: 'e-icons e-maximize-2',
align: 'Right',
tooltip: 'Expand'
},
{
// Close button (right, disabled)
type: 'Button',
iconCss: 'e-icons e-close',
align: 'Right',
disabled: true,
tooltip: 'Close'
},
{
// Info button (right, visible)
type: 'Button',
iconCss: 'e-icons e-info',
align: 'Right',
visible: true,
tooltip: 'Information'
}
]
};Toolbar Positioning
Top Position
Toolbar appears above the input:
<div class="toolbar-top">
<!-- Toolbar items here -->
</div>
<textarea class="prompt-input"></textarea>Bottom Position
Toolbar appears below the input:
<textarea class="prompt-input"></textarea>
<div class="toolbar-bottom">
<!-- Toolbar items here -->
</div>Inline Position
Toolbar items mixed with input (default):
<div class="toolbar-inline">
<textarea class="prompt-input"></textarea>
<div class="toolbar-items">
<!-- Inline items -->
</div>
</div>Tab Key Navigation
Enabling Tab Navigation in Toolbar
public inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
iconCss: 'e-icons e-refresh',
align: 'Right',
type: 'Button'
}
],
// Enable tab key navigation
enableKeyboardNav: true
}Tab Order
Control focus order between toolbar items:
.toolbar-item {
tabindex: 0; /* Focusable */
}
.toolbar-item:focus {
outline: 2px solid #2196f3;
outline-offset: 2px;
}Complete Navigation Example
export class AppComponent {
public inlineToolbarSettings: InlineToolbarSettingsModel = {
items: [
{
iconCss: 'e-icons e-undo',
align: 'Left',
type: 'Button',
tooltip: 'Undo (Alt+Z)'
},
{
iconCss: 'e-icons e-redo',
align: 'Left',
type: 'Button',
tooltip: 'Redo (Alt+Y)'
},
{
type: 'Separator',
align: 'Left'
},
{
iconCss: 'e-icons e-copy',
align: 'Right',
type: 'Button',
tooltip: 'Copy (Ctrl+C)'
},
{
iconCss: 'e-icons e-cut',
align: 'Right',
type: 'Button',
tooltip: 'Cut (Ctrl+X)'
},
{
iconCss: 'e-icons e-paste',
align: 'Right',
type: 'Button',
tooltip: 'Paste (Ctrl+V)'
}
]
};
}Styling Guidelines
Custom Toolbar CSS
/* Toolbar container */
.e-toolbar {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 8px;
border-radius: 4px;
}
/* Toolbar buttons */
.e-toolbar-item {
margin: 0 4px;
border-radius: 4px;
}
.e-toolbar-item:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.e-toolbar-item:focus {
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.5);
}
/* Custom button styles */
.toolbar-refresh {
color: #fff;
}
.toolbar-user {
background: rgba(255, 255, 255, 0.1);
padding: 4px 8px;
border-radius: 50%;
}
/* Separator */
.e-toolbar-separator {
background-color: rgba(255, 255, 255, 0.3);
}