Skip to main content

Style Customization

React Widget provides multi-level style customization capabilities, from simple class name overriding to complete custom rendering.

Customization Levels​

LevelMethodUse Case
1CSS class name overrideAdjust colors, spacing, fonts, etc.
2style attributeInline styles for individual components
3Custom iconsReplace built-in icons
4children renderingComplete 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 NameDescription
.apk-pilot-kitRoot container
.apk-pilot-kit__contentContent area

ConversationList​

Class NameDescription
.apk-conversation-listRoot container
.apk-conversation-list--mobileMobile style
.apk-conversation-list--desktopDesktop style
.apk-conversation-list__innerInner scroll container
.apk-conversation-list__follow-buttonScroll follow button

Conversation​

Class NameDescription
.apk-conversationRoot container
.apk-conversation--clientUser message
.apk-conversation--aiAI message
.apk-conversation__content-textText content

ControlPanel​

Class NameDescription
.apk-control-panelRoot container
.apk-control-panel--mobileMobile style
.apk-control-panel__innerInner container
.apk-control-panel__mode-btnMode switch button
.apk-control-panel__inputInput box
.apk-control-panel__send-btnSend button
.apk-control-panel__mic-btnMicrophone button
.apk-control-panel__hangup-btnHangup button

Input​

Class NameDescription
.apk-inputRoot container
.apk-input--mobileMobile style
.apk-input__fieldInput box
.apk-input__send-iconSend icon
.apk-input--errorError state
.apk-input--disabledDisabled 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)​

Tip

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:

  1. First try className + CSS
  2. If not enough, try style attribute
  3. Use children rendering only when structure changes are needed