Skip to main content

Style Customization

Vue 3 Widget provides multi-level style customization capabilities, from simple class name overrides to fully custom rendering.

Customization Levels​

LevelMethodUse Case
1CSS class name overrideAdjust colors, spacing, fonts, etc.
2style propertyInline styles for individual components
3Custom icons (slots)Replace built-in icons
4scoped slots renderingFully custom component structure

CSS Class Name Override​

Naming Convention​

All components use BEM naming convention, prefixed with 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 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
.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--desktopDesktop style
.apk-input__fieldInput field
.apk-input__send-iconSend icon
.apk-input--errorError state
.apk-input--disabledDisabled state

More Class Names​

See each component documentation's "Style Customization" section for details.

class Property​

Each component supports class property, used to add custom class names:

<template>
<ControlPanel class="my-control-panel" />
</template>

<style>
.my-control-panel {
margin-bottom: 20px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
</style>

style Property​

Use style property to set inline styles:

<template>
<ConversationList
:style="{
maxHeight: '400px',
borderRadius: '16px',
backgroundColor: 'rgba(255, 255, 255, 0.9)'
}"
/>
</template>

Custom Icons (Slots)​

Multiple components support customizing icons through slots:

ControlPanel Icons​

<template>
<ControlPanel>
<template #muteIcon><MuteIcon /></template>
<template #unmuteIcon><UnmuteIcon /></template>
<template #hangupIcon><HangupIcon /></template>
<template #asrIcon><MicIcon /></template>
<template #keyboardIcon><KeyboardIcon /></template>
<template #sendIcon><SendIcon /></template>
</ControlPanel>
</template>

ConversationList Icons​

<template>
<ConversationList>
<template #closeIcon><CloseIcon /></template>
</ConversationList>
</template>

RecommendedQuestions Icons​

<template>
<RecommendedQuestions>
<template #arrowIcon><ArrowIcon /></template>
</RecommendedQuestions>
</template>

Scoped Slots Rendering​

You can fully customize component rendering through scoped slots:

ConversationList​

<template>
<ConversationList v-slot="{conversations, latestConversation}">
<div class="my-conversation-list">
<h3>Conversation History</h3>
<div
v-for="conv in conversations"
:key="conv.id"
:class="['my-message', `my-message--${conv.type}`]"
>
<span class="speaker">
{{ conv.type === 'client' ? 'Me' : 'AI' }}
</span>
<p>{{ conv.text }}</p>
</div>
</div>
</ConversationList>
</template>

Conversation​

<template>
<Conversation
:conversation="conv"
v-slot="{contents, fullText, type, isCompleted}"
>
<div :class="['custom-bubble', type]">
<p>{{ fullText }}</p>
<span v-if="!isCompleted" class="typing-indicator">...</span>
</div>
</Conversation>
</template>

Subtitle​

<template>
<Subtitle v-slot="{speakerName, fullText, isExpanded, toggleExpand}">
<div class="custom-subtitle">
<strong>{{ speakerName }}:</strong>
<span>{{ fullText }}</span>
<button @click="toggleExpand">
{{ isExpanded ? 'Collapse' : 'Expand' }}
</button>
</div>
</Subtitle>
</template>

Input​

<template>
<Input v-slot="{value, setValue, handleSend, disabled, loading}">
<div class="custom-input">
<textarea
:value="value"
@input="e => setValue(e.target.value)"
:disabled="disabled"
placeholder="Enter message..."
/>
<button @click="handleSend" :disabled="loading || !value">
{{ loading ? 'Sending...' : 'Send' }}
</button>
</div>
</Input>
</template>

StartupScreen​

<template>
<StartupScreen :show="showStartup" v-slot="{onStart, isActivating}">
<div class="custom-startup">
<img src="/logo.png" alt="Logo" />
<h1>Welcome to Digital Employee</h1>
<button @click="onStart" :disabled="isActivating">
{{ isActivating ? 'Activating...' : 'Start Conversation' }}
</button>
</div>
</StartupScreen>
</template>

CSS Variables (Planned)​

Note

CSS variable support is being planned, future versions will provide more convenient theme customization methods.

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 Scoped Styles​

Vue SFC scoped styles avoid global pollution:

<template>
<ControlPanel class="my-control-panel" />
</template>

<style scoped>
.my-control-panel {
/* Styles */
}

/* Deep selectors for overriding child component styles */
:deep(.apk-control-panel__input) {
border-color: #007bff;
}
</style>

2. Keep Original Class Names​

When overriding styles, keep original class names to ensure responsive and other features work correctly:

<template>
<!-- ✅ Recommended -->
<ControlPanel class="my-custom-class" />

<!-- ❌ Avoid: Completely replacing internal structure causing feature loss -->
</template>

3. Prioritize CSS Overrides​

For simple style adjustments, prioritize CSS overrides over scoped slots rendering:

/* ✅ Recommended: Simple style adjustments */
.apk-conversation--ai {
background: #f0f0f0;
}
<template>
<!-- ❌ Overused: Simple styles don't need custom rendering -->
<Conversation :conversation="conv" v-slot="{fullText}">
<div style="background: #f0f0f0">{{ fullText }}</div>
</Conversation>
</template>

4. Progressive Customization​

Start with the simplest approach, upgrade as needed:

  1. First try class + CSS
  2. If not enough, try style property
  3. Use scoped slots rendering when structural changes are needed