Skip to main content
The BuilderSettingsHelper handles basic feature toggles. For deeper customizations, modify the configuration JSON, theme settings, or component props directly.

Understanding the Customization Architecture

The Flutter UI Kit Builder uses these main files for customization:
FilePurposeWhen to Modify
cometchat-builder-settings.jsonFeature flags and configuration constantsFunctional changes (enable/disable features)
BuilderSettingsHelperUtility class for loading and accessing settingsRuntime configuration access
pubspec.yamlFont and asset declarationsAdding custom fonts or assets
The cometchat-builder-settings.json file is the source of truth for your Builder configuration. Update it and reload to apply changes.

Using BuilderSettingsHelper

The BuilderSettingsHelper provides access to your Builder configuration throughout your app.

Loading Configuration

import 'package:chat_builder/utils/builder_settings_helper.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Load settings from assets
  await BuilderSettingsHelper.loadFromAsset();
  
  runApp(const MyApp());
}

Accessing Settings

import 'package:chat_builder/utils/builder_settings_helper.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final settings = BuilderSettingsHelper.settings;
    
    // Access chat features
    final chatFeatures = settings.chatFeatures;
    final isPhotosEnabled = chatFeatures.coreMessagingExperience.photosSharing;
    
    // Access style settings
    final style = settings.style;
    final brandColor = style.color.brandColor;
    
    // Access layout settings
    final layout = settings.layout;
    final tabs = layout.tabs;
    
    return Container(/* ... */);
  }
}

Theme Customization

Applying Builder Theme to UI Kit

Apply the Builder configuration colors to your Flutter theme:
import 'package:flutter/material.dart';
import 'package:chat_builder/utils/builder_settings_helper.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final style = BuilderSettingsHelper.settings.style;
    
    return MaterialApp(
      theme: ThemeData(
        primaryColor: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
        colorScheme: ColorScheme.light(
          primary: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
        ),
        textTheme: TextTheme(
          bodyLarge: TextStyle(
            color: Color(int.parse(style.color.primaryTextLight.replaceFirst('#', '0xFF'))),
          ),
          bodyMedium: TextStyle(
            color: Color(int.parse(style.color.secondaryTextLight.replaceFirst('#', '0xFF'))),
          ),
        ),
        fontFamily: style.typography.font,
      ),
      darkTheme: ThemeData.dark().copyWith(
        primaryColor: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
        colorScheme: ColorScheme.dark(
          primary: Color(int.parse(style.color.brandColor.replaceFirst('#', '0xFF'))),
        ),
        textTheme: TextTheme(
          bodyLarge: TextStyle(
            color: Color(int.parse(style.color.primaryTextDark.replaceFirst('#', '0xFF'))),
          ),
          bodyMedium: TextStyle(
            color: Color(int.parse(style.color.secondaryTextDark.replaceFirst('#', '0xFF'))),
          ),
        ),
        fontFamily: style.typography.font,
      ),
      themeMode: _getThemeMode(style.theme),
      home: HomeScreen(),
    );
  }
  
  ThemeMode _getThemeMode(String theme) {
    switch (theme) {
      case 'light':
        return ThemeMode.light;
      case 'dark':
        return ThemeMode.dark;
      default:
        return ThemeMode.system;
    }
  }
}

Custom Color Utilities

Create a utility class for working with Builder colors:
import 'package:flutter/material.dart';
import 'package:chat_builder/utils/builder_settings_helper.dart';

class BuilderColors {
  static Color get brandColor {
    final hex = BuilderSettingsHelper.settings.style.color.brandColor;
    return _hexToColor(hex);
  }
  
  static Color get primaryTextLight {
    final hex = BuilderSettingsHelper.settings.style.color.primaryTextLight;
    return _hexToColor(hex);
  }
  
  static Color get primaryTextDark {
    final hex = BuilderSettingsHelper.settings.style.color.primaryTextDark;
    return _hexToColor(hex);
  }
  
  static Color get secondaryTextLight {
    final hex = BuilderSettingsHelper.settings.style.color.secondaryTextLight;
    return _hexToColor(hex);
  }
  
  static Color get secondaryTextDark {
    final hex = BuilderSettingsHelper.settings.style.color.secondaryTextDark;
    return _hexToColor(hex);
  }
  
  static Color _hexToColor(String hex) {
    return Color(int.parse(hex.replaceFirst('#', '0xFF')));
  }
}

Custom Font Integration

Step 1: Add Font Files

Add your custom font files to the assets/fonts/ directory.

Step 2: Update pubspec.yaml

Register your custom fonts:
flutter:
  fonts:
    - family: YourCustomFont
      fonts:
        - asset: assets/fonts/your_font_regular.ttf
        - asset: assets/fonts/your_font_medium.ttf
          weight: 500
        - asset: assets/fonts/your_font_bold.ttf
          weight: 700

Step 3: Apply Custom Font

Update the configuration JSON or apply programmatically:
// In your theme configuration
ThemeData(
  fontFamily: 'YourCustomFont',
  // ... other theme settings
)

Component-Level Customizations

Conditional Rendering Based on Features

Use the configuration to conditionally render UI elements:
import 'package:chat_builder/utils/builder_settings_helper.dart';

class MessageComposer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final chatFeatures = BuilderSettingsHelper.settings.chatFeatures;
    final core = chatFeatures.coreMessagingExperience;
    final engagement = chatFeatures.deeperUserEngagement;
    
    return Row(
      children: [
        // Always show text input
        Expanded(child: TextField()),
        
        // Conditionally show attachment options
        if (core.photosSharing)
          IconButton(
            icon: Icon(Icons.photo),
            onPressed: () => _attachPhoto(),
          ),
        
        if (core.fileSharing)
          IconButton(
            icon: Icon(Icons.attach_file),
            onPressed: () => _attachFile(),
          ),
        
        if (engagement.voiceNotes)
          IconButton(
            icon: Icon(Icons.mic),
            onPressed: () => _recordVoiceNote(),
          ),
        
        if (engagement.stickers)
          IconButton(
            icon: Icon(Icons.emoji_emotions),
            onPressed: () => _showStickers(),
          ),
      ],
    );
  }
}

Customizing Message Options

Control which message options appear based on configuration:
class MessageOptionsSheet extends StatelessWidget {
  final Message message;
  
  const MessageOptionsSheet({required this.message});
  
  @override
  Widget build(BuildContext context) {
    final chatFeatures = BuilderSettingsHelper.settings.chatFeatures;
    final core = chatFeatures.coreMessagingExperience;
    final engagement = chatFeatures.deeperUserEngagement;
    final moderator = chatFeatures.moderatorControls;
    
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        if (core.quotedReplies)
          ListTile(
            leading: Icon(Icons.reply),
            title: Text('Reply'),
            onTap: () => _handleReply(),
          ),
        
        if (core.threadConversationAndReplies)
          ListTile(
            leading: Icon(Icons.forum),
            title: Text('Reply in Thread'),
            onTap: () => _handleThreadReply(),
          ),
        
        if (engagement.reactions)
          ListTile(
            leading: Icon(Icons.add_reaction),
            title: Text('React'),
            onTap: () => _handleReaction(),
          ),
        
        if (core.editMessage && _isOwnMessage())
          ListTile(
            leading: Icon(Icons.edit),
            title: Text('Edit'),
            onTap: () => _handleEdit(),
          ),
        
        if (core.deleteMessage && _isOwnMessage())
          ListTile(
            leading: Icon(Icons.delete),
            title: Text('Delete'),
            onTap: () => _handleDelete(),
          ),
        
        if (moderator.reportMessage)
          ListTile(
            leading: Icon(Icons.flag),
            title: Text('Report'),
            onTap: () => _handleReport(),
          ),
      ],
    );
  }
}

Layout Customization

Dynamic Tab Configuration

import 'package:chat_builder/utils/builder_settings_helper.dart';

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final layout = BuilderSettingsHelper.settings.layout;
    
    if (!layout.withSideBar) {
      return SingleChatView();
    }
    
    final tabs = layout.tabs;
    
    return DefaultTabController(
      length: tabs.length,
      child: Scaffold(
        appBar: AppBar(
          bottom: TabBar(
            tabs: [
              if (tabs.contains('chats'))
                Tab(icon: Icon(Icons.chat), text: 'Chats'),
              if (tabs.contains('calls'))
                Tab(icon: Icon(Icons.call), text: 'Calls'),
              if (tabs.contains('users'))
                Tab(icon: Icon(Icons.people), text: 'Users'),
              if (tabs.contains('groups'))
                Tab(icon: Icon(Icons.group), text: 'Groups'),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            if (tabs.contains('chats')) ChatsScreen(),
            if (tabs.contains('calls')) CallsScreen(),
            if (tabs.contains('users')) UsersScreen(),
            if (tabs.contains('groups')) GroupsScreen(),
          ],
        ),
      ),
    );
  }
}

Call Features Customization

Conditional Call Buttons

class ChatHeader extends StatelessWidget {
  final bool isGroup;
  
  const ChatHeader({required this.isGroup});
  
  @override
  Widget build(BuildContext context) {
    final callFeatures = BuilderSettingsHelper.settings.callFeatures;
    final calling = callFeatures.voiceAndVideoCalling;
    
    return AppBar(
      actions: [
        if (isGroup) ...[
          if (calling.groupVoiceConference)
            IconButton(
              icon: Icon(Icons.call),
              onPressed: () => _startGroupVoiceCall(),
            ),
          if (calling.groupVideoConference)
            IconButton(
              icon: Icon(Icons.videocam),
              onPressed: () => _startGroupVideoCall(),
            ),
        ] else ...[
          if (calling.oneOnOneVoiceCalling)
            IconButton(
              icon: Icon(Icons.call),
              onPressed: () => _startVoiceCall(),
            ),
          if (calling.oneOnOneVideoCalling)
            IconButton(
              icon: Icon(Icons.videocam),
              onPressed: () => _startVideoCall(),
            ),
        ],
      ],
    );
  }
}

Reloading Configuration

Refresh Settings at Runtime

import 'package:chat_builder/utils/builder_settings_helper.dart';

class SettingsScreen extends StatelessWidget {
  Future<void> _reloadConfiguration() async {
    // Reload from assets
    await BuilderSettingsHelper.loadFromAsset();
    
    // Trigger UI rebuild
    // Use a state management solution to notify listeners
  }
  
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _reloadConfiguration,
      child: Text('Reload Configuration'),
    );
  }
}