Style Customization
React Widget provides multi-level style customization capabilities, from simple class name overriding to complete custom rendering.
Customization Levels
| Level | Method | Use Case |
|---|---|---|
| 1 | CSS class name override | Adjust colors, spacing, fonts, etc. |
| 2 | style attribute | Inline styles for individual components |
| 3 | Custom icons | Replace built-in icons |
| 4 | children rendering | Complete custom component structure |
CSS Class Name Override
Naming Convention
All components use BEM naming convention with prefix apk- (AaaS Pilot Kit):
.apk-{component-name} /* Block */
.apk-{component-name}__{element-name} /* Element */
.apk-{component-name}--{modifier} /* Modifier */
Example
/* Modify control panel background */
.apk-control-panel {
background: rgba(0, 0, 0, 0.8);
}
/* Modify input box style */
.apk-control-panel__input {
border: 2px solid #007bff;
border-radius: 25px;
}
/* Modify mobile button size */
.apk-control-panel--mobile .apk-control-panel__mic-btn {
width: 60px;
height: 60px;
}
Component Class Name Quick Reference
PilotKit
| Class Name | Description |
|---|---|
.apk-pilot-kit | Root container |
.apk-pilot-kit__content | Content area |
ConversationList
| Class Name | Description |
|---|---|
.apk-conversation-list | Root container |
.apk-conversation-list--mobile | Mobile style |
.apk-conversation-list--desktop | Desktop style |
.apk-conversation-list__inner | Inner scroll container |
.apk-conversation-list__follow-button | Scroll follow button |
Conversation
| Class Name | Description |
|---|---|
.apk-conversation | Root container |
.apk-conversation--client | User message |
.apk-conversation--ai | AI message |
.apk-conversation__content-text | Text content |
ControlPanel
| Class Name | Description |
|---|---|
.apk-control-panel | Root container |
.apk-control-panel--mobile | Mobile style |
.apk-control-panel__inner | Inner container |
.apk-control-panel__mode-btn | Mode switch button |
.apk-control-panel__input | Input box |
.apk-control-panel__send-btn | Send button |
.apk-control-panel__mic-btn | Microphone button |
.apk-control-panel__hangup-btn | Hangup button |
Input
| Class Name | Description |
|---|---|
.apk-input | Root container |
.apk-input--mobile | Mobile style |
.apk-input__field | Input box |
.apk-input__send-icon | Send icon |
.apk-input--error | Error state |
.apk-input--disabled | Disabled state |
More Class Names
See the "Style Customization" section in each component's documentation.
className Attribute
Each component supports className attribute for adding custom class names:
<ControlPanel className="my-control-panel" />
.my-control-panel {
margin-bottom: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
style Attribute
Use style attribute to set inline styles:
<ConversationList
style={{
maxHeight: 400,
borderRadius: 16,
backgroundColor: 'rgba(255, 255, 255, 0.9)'
}}
/>
Custom Icons
Multiple components support custom icons:
ControlPanel Icons
<ControlPanel
muteIcon={<MuteIcon />}
unmuteIcon={<UnmuteIcon />}
hangupIcon={<HangupIcon />}
asrIcon={<MicIcon />}
keyboardIcon={<KeyboardIcon />}
sendIcon={<SendIcon />}
/>
ConversationList Icon
<ConversationList
closeIcon={<CloseIcon />}
/>
RecommendedQuestions Icon
<RecommendedQuestions
arrowIcon={<ArrowIcon />}
/>
children Rendering
Through children function you can completely customize component rendering:
ConversationList
<ConversationList>
{({conversations, latestConversation}) => (
<div className="my-conversation-list">
<h3>Conversation History</h3>
{conversations.map(conv => (
<div
key={conv.id}
className={`my-message my-message--${conv.type}`}
>
<span className="speaker">
{conv.type === 'client' ? 'Me' : 'AI'}
</span>
<p>{conv.text}</p>
</div>
))}
</div>
)}
</ConversationList>
Conversation
<Conversation conversation={conv}>
{({contents, fullText, type, isCompleted}) => (
<div className={`custom-bubble ${type}`}>
<p>{fullText}</p>
{!isCompleted && <span className="typing-indicator">...</span>}
</div>
)}
</Conversation>
Subtitle
<Subtitle>
{({speakerName, fullText, isExpanded, toggleExpand}) => (
<div className="custom-subtitle">
<strong>{speakerName}:</strong>
<span>{fullText}</span>
<button onClick={toggleExpand}>
{isExpanded ? 'Collapse' : 'Expand'}
</button>
</div>
)}
</Subtitle>
Input
<Input>
{({value, setValue, handleSend, disabled, loading}) => (
<div className="custom-input">
<textarea
value={value}
onChange={e => setValue(e.target.value)}
disabled={disabled}
placeholder="Type your message..."
/>
<button onClick={handleSend} disabled={loading || !value}>
{loading ? 'Sending...' : 'Send'}
</button>
</div>
)}
</Input>
StartupScreen
<StartupScreen show={showStartup}>
{({onStart, isActivating}) => (
<div className="custom-startup">
<img src="/logo.png" alt="Logo" />
<h1>Welcome to Digital Employee</h1>
<button onClick={onStart} disabled={isActivating}>
{isActivating ? 'Activating...' : 'Start Conversation'}
</button>
</div>
)}
</StartupScreen>
CSS Variables (Planned)
CSS variable support is being planned, future versions will provide more convenient theme customization.
Expected variable examples:
:root {
--apk-primary-color: #007bff;
--apk-background-color: rgba(255, 255, 255, 0.9);
--apk-text-color: #333;
--apk-border-radius: 20px;
--apk-font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
Theme Examples
Dark Theme
/* Dark theme */
.dark-theme .apk-conversation-list {
background: rgba(30, 30, 30, 0.95);
}
.dark-theme .apk-conversation--ai {
background: rgba(50, 50, 50, 0.9);
color: #fff;
}
.dark-theme .apk-conversation--client {
background: #007bff;
color: #fff;
}
.dark-theme .apk-control-panel {
background: rgba(40, 40, 40, 0.9);
}
.dark-theme .apk-control-panel__input {
background: rgba(60, 60, 60, 0.9);
color: #fff;
border-color: rgba(100, 100, 100, 0.5);
}
Rounded Theme
/* Rounded theme */
.rounded-theme .apk-conversation {
border-radius: 24px;
}
.rounded-theme .apk-control-panel__input {
border-radius: 30px;
}
.rounded-theme .apk-control-panel__mic-btn,
.rounded-theme .apk-control-panel__send-btn {
border-radius: 50%;
}
Corporate Theme
/* Corporate brand theme */
.corporate-theme .apk-conversation--ai {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
}
.corporate-theme .apk-control-panel__mic-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.corporate-theme .apk-subtitle {
border-left: 3px solid #667eea;
padding-left: 12px;
}
Best Practices
1. Use CSS Modules or Scoped Styles
Avoid global style pollution:
// styles.module.css
.myControlPanel {
/* Styles */
}
// Component.tsx
import styles from './styles.module.css';
<ControlPanel className={styles.myControlPanel} />
2. Keep Original Class Names
When overriding styles, preserve original class names to ensure responsive features work properly:
// ✅ Recommended
<ControlPanel className="my-custom-class" />
// ❌ Avoid: Completely replacing internal structure causing feature loss
3. Prioritize CSS Override
For simple style adjustments, prioritize CSS override over children rendering:
/* ✅ Recommended: Simple style adjustment */
.apk-conversation--ai {
background: #f0f0f0;
}
// ❌ Overused: Simple styles don't need custom rendering
<Conversation conversation={conv}>
{({fullText}) => (
<div style={{background: '#f0f0f0'}}>{fullText}</div>
)}
</Conversation>
4. Progressive Customization
Start with the simplest approach, upgrade as needed:
- First try
className+ CSS - If not enough, try
styleattribute - Use
childrenrendering only when structure changes are needed
Related
- Responsive Adaptation - Responsive style customization
- PilotKit - Core component styles
- Control Components - Control panel styles
- Message Components - Message component styles