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