Skip to content

Custom Styling and State Classes

Overview

The Wabee Chat widget provides CSS state classes that allow you to customize the appearance based on the current chat state. These classes are applied directly to the Layout component and can be used to create custom loading animations, status indicators, and visual feedback.

Setup

To enable state classes, set enableStateClasses: true in your widget initialization:

window.WabeeChat.init({
    target: '#wabee-chat-container',
    apiKey: 'your_api_key_here',
    agentUrl: 'https://your-agent.wabee.ai/core/v1',
    sseUrl: 'https://notifications-hub.wabee.ai/events',
    enableStateClasses: true,  // Required for state classes
    showStatusText: true       // Optional: show/hide status text
});

Available State Classes

State Classes (applied to Layout element)

  • .wabee-chat-idle - No activity
  • .wabee-chat-processing - Processing user input
  • .wabee-chat-generating - AI generating response
  • .wabee-chat-streaming - AI typing text output
  • .wabee-chat-loading - Chat loading
  • .wabee-chat-session-loading - Session loading

Internal Element Classes

  • .wabee-loading-container - Container for loading elements
  • .wabee-loading-indicator - Pulsing status indicator
  • .wabee-loading-status-text - Status text element
  • .wabee-loading-spinner - Spinner element
  • .wabee-input-loading-container - Input loading container
  • .wabee-input-loading-spinner - Input spinner
  • .wabee-input-stop-button - Stop button
  • .wabee-conversation-loading - Conversation loading
  • .wabee-conversation-loading-icon - Conversation loading icon

Custom Loading Animations

Status Bar Implementation

The state classes are applied directly to the chat layout element, so target them directly:

/* Add position relative to all state classes */
.wabee-chat-idle,
.wabee-chat-processing,
.wabee-chat-generating,
.wabee-chat-streaming,
.wabee-chat-loading,
.wabee-chat-session-loading {
    position: relative;
}

/* Create a status bar at the top */
.wabee-chat-idle::before,
.wabee-chat-processing::before,
.wabee-chat-generating::before,
.wabee-chat-streaming::before,
.wabee-chat-loading::before,
.wabee-chat-session-loading::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    z-index: 1000;
}

/* State-specific colors */
.wabee-chat-idle::before {
    background-color: #C5E85C;
}

.wabee-chat-processing::before {
    background-color: #ffc107;
    animation: progress-bar 2s infinite;
}

.wabee-chat-generating::before {
    background-color: #6f42c1;
    animation: progress-bar 1.5s infinite;
}

.wabee-chat-streaming::before {
    background-color: #dc3545;
    animation: streaming-bar 1s infinite;
}

.wabee-chat-loading::before,
.wabee-chat-session-loading::before {
    background-color: #6c757d;
    animation: loading-bar 1.5s infinite;
}

/* Animations */
@keyframes progress-bar {
    0% { transform: scaleX(0); }
    50% { transform: scaleX(0.8); }
    100% { transform: scaleX(1); }
}

@keyframes streaming-bar {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

@keyframes loading-bar {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
}

Customizing Internal Elements

You can also style the internal loading elements within different states:

/* Style the loading indicator during generating state */
.wabee-chat-generating .wabee-loading-indicator {
    background: #6f42c1 !important;
    box-shadow: 0 0 12px rgba(111, 66, 193, 0.5) !important;
}

/* Style the loading indicator during streaming state */
.wabee-chat-streaming .wabee-loading-indicator {
    background: #dc3545 !important;
    box-shadow: 0 0 12px rgba(220, 53, 69, 0.5) !important;
}

/* Style other loading elements */
.wabee-chat-processing .wabee-loading-spinner {
    color: #ffc107;
}

Complete Implementation Example

Here's a working example based on the examples above:

<!DOCTYPE html>
<html>
<head>
    <style>
        /* State classes are applied directly to the Layout component */
        .wabee-chat-idle,
        .wabee-chat-processing,
        .wabee-chat-generating,
        .wabee-chat-streaming,
        .wabee-chat-loading,
        .wabee-chat-session-loading {
            position: relative;
        }

        /* Status bar implementation */
        .wabee-chat-idle::before,
        .wabee-chat-processing::before,
        .wabee-chat-generating::before,
        .wabee-chat-streaming::before,
        .wabee-chat-loading::before,
        .wabee-chat-session-loading::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 3px;
            z-index: 1000;
        }

        /* State-specific colors */
        .wabee-chat-idle::before { background-color: #C5E85C; }
        .wabee-chat-processing::before { 
            background-color: #ffc107; 
            animation: progress-bar 2s infinite; 
        }
        .wabee-chat-generating::before { 
            background-color: #6f42c1; 
            animation: progress-bar 1.5s infinite; 
        }
        .wabee-chat-streaming::before { 
            background-color: #dc3545; 
            animation: streaming-bar 1s infinite; 
        }
        .wabee-chat-loading::before,
        .wabee-chat-session-loading::before { 
            background-color: #6c757d; 
            animation: loading-bar 1.5s infinite; 
        }

        /* Internal element styling */
        .wabee-chat-generating .wabee-loading-indicator {
            background: #6f42c1 !important;
            box-shadow: 0 0 12px rgba(111, 66, 193, 0.5) !important;
        }

        /* Animations */
        @keyframes progress-bar {
            0% { transform: scaleX(0); }
            50% { transform: scaleX(0.8); }
            100% { transform: scaleX(1); }
        }

        @keyframes streaming-bar {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.3; }
        }

        @keyframes loading-bar {
            0% { transform: translateX(-100%); }
            100% { transform: translateX(100%); }
        }
    </style>
</head>
<body>
    <div id="wabee-chat-container"></div>

    <script src="https://platform.wabee.ai/scripts/wabee-chat-browser.umd_v1_2_25.js"></script>
    <script>
        window.WabeeChat.init({
            target: '#wabee-chat-container',
            apiKey: 'your_api_key_here',
            agentUrl: 'https://your-agent.wabee.ai/core/v1',
            sseUrl: 'https://notifications-hub.wabee.ai/events',
            width: '100%',
            height: '100%',
            enableStateClasses: true,  // Required for state classes
            showStatusText: true       // Optional: show/hide status text
        });
    </script>
</body>
</html>

Best Practices

Performance Considerations

  1. Use CSS Transitions: Smooth state changes with CSS transitions instead of JavaScript
  2. Limit Animation Complexity: Keep animations lightweight to avoid performance issues
  3. Test on Mobile: Ensure state indicators work well on touch devices

Accessibility

  1. Color Contrast: Ensure sufficient color contrast for all state indicators
  2. Screen Reader Support: Use aria-label attributes for visual-only indicators
  3. Reduced Motion: Respect prefers-reduced-motion for users who prefer minimal animations
@media (prefers-reduced-motion: reduce) {
    .wabee-chat-streaming::before,
    .wabee-chat-processing::before,
    .wabee-chat-generating::before {
        animation: none;
    }
}

Browser Compatibility

  • State classes work in all modern browsers
  • CSS animations are supported in IE10+
  • For older browsers, provide fallback styling without animations

Troubleshooting

Common Issues

  1. State classes not working: Ensure enableStateClasses: true is set in initialization
  2. CSS not applying: State classes are applied to the Layout component, not a container div
  3. Animations not showing: Check browser console for state class changes to verify they're being applied

Debugging State Changes

Use browser developer tools to inspect the chat container and verify which state classes are being applied:

// Monitor state class changes in browser console
const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
            console.log('State classes changed:', mutation.target.className);
        }
    });
});

// Find the Layout element (it will have ant-layout class)
const layoutElement = document.querySelector('.ant-layout');
if (layoutElement) {
    observer.observe(layoutElement, { attributes: true });
}

State Lifecycle

The typical state flow is: 1. idle → User starts typing 2. processing → User submits message 3. generating → AI processes and prepares response 4. streaming → AI outputs text tokens 5. idle → Response complete

Multiple states can be active simultaneously (e.g., generating + loading).

Advanced Examples

Custom State Indicators

/* Add visual feedback for each state */
.wabee-chat-idle {
    border-left: 4px solid #C5E85C;
}

.wabee-chat-processing {
    border-left: 4px solid #ffc107;
}

.wabee-chat-generating {
    border-left: 4px solid #6f42c1;
}

.wabee-chat-streaming {
    border-left: 4px solid #dc3545;
}

State-Specific Styling

/* Change background during different states */
.wabee-chat-processing {
    background-color: rgba(255, 193, 7, 0.05);
}

.wabee-chat-generating {
    background-color: rgba(111, 66, 193, 0.05);
}

.wabee-chat-streaming {
    background-color: rgba(220, 53, 69, 0.05);
}

Multiple Element Targeting

/* Style multiple internal elements */
.wabee-chat-generating .wabee-loading-indicator,
.wabee-chat-generating .wabee-loading-spinner {
    color: #6f42c1;
}

.wabee-chat-streaming .wabee-loading-status-text {
    color: #dc3545;
    font-weight: bold;
}

Next Steps