Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
cometchat avatar

Cometchat Flutter V6 Theming

  • 5 installs
  • 70 repo stars
  • Updated June 23, 2026
  • cometchat/cometchat-skills

Customize the visual appearance of CometChat Flutter UIKit v6 components using the color palette, spacing, typography, and dark/light theme modes.

About

Explains the three-layer ThemeExtension-based theme system for CometChat Flutter UIKit v6. A developer uses it to change colors, fonts, spacing, and dark-mode appearance of chat components.

  • Three layers: CometChatColorPalette, CometChatSpacing, CometChatTypography
  • Access theme tokens via CometChatThemeHelper static helpers

Cometchat Flutter V6 Theming by the numbers

  • 5 all-time installs (skills.sh)
  • Ranked #1,515 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cometchat/cometchat-skills --skill cometchat-flutter-v6-theming

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs5
repo stars70
Last updatedJune 23, 2026
Repositorycometchat/cometchat-skills

What it does

Customize the visual appearance of CometChat Flutter UIKit v6 components using the color palette, spacing, typography, and dark/light theme modes.

Files

SKILL.mdMarkdownGitHub ↗

CometChat Flutter UIKit — Theming & Styling

How to customize the visual appearance of all CometChat components.

Theme System Architecture

Three layers, resolved via Flutter's ThemeExtension system:

1. CometChatColorPalette — all colors (primary, neutral, alert, background, text, icon, button, border) 2. CometChatSpacing — spacing tokens 3. CometChatTypography — text styles (heading1-4, body, caption1-2, button, link, title)

Access via static helpers:

final colors = CometChatThemeHelper.getColorPalette(context);
final spacing = CometChatThemeHelper.getSpacing(context);
final typography = CometChatThemeHelper.getTypography(context);

Applying a Custom Theme

Register CometChatColorPalette as a ThemeExtension on your ThemeData:

MaterialApp(
  theme: ThemeData(
    brightness: Brightness.light,
    extensions: [
      CometChatColorPalette(
        primary: const Color(0xFF6852D6),
        background1: Colors.white,
        textPrimary: const Color(0xFF141414),
        // ... override only what you need, rest falls back to defaults
      ),
    ],
  ),
  darkTheme: ThemeData(
    brightness: Brightness.dark,
    extensions: [
      CometChatColorPalette(
        primary: const Color(0xFF604CC3),
        background1: const Color(0xFF141414),
        textPrimary: Colors.white,
      ),
    ],
  ),
)

Note: CometChatColorPalette does NOT have a const constructor (it has mutable default fields for white, black, transparent). Don't try const CometChatColorPalette(...) — it won't compile.

Dark Mode

CometChatThemeMode controls how brightness is resolved:

// Follow system setting (default)
CometChatThemeMode.mode = ThemeMode.system;

// Force light
CometChatThemeMode.mode = ThemeMode.light;

// Force dark
CometChatThemeMode.mode = ThemeMode.dark;

The helper reads brightness via:

// ThemeMode.system → MediaQuery.of(context).platformBrightness
// ThemeMode.light → Brightness.light
// ThemeMode.dark → Brightness.dark

Color Palette Tokens

CategoryTokensDefault Source
Primaryprimary#6852D6 light / #604CC3 dark
Extended PrimaryextendedPrimary50900Auto-generated from primary via blend
Neutralneutral5090010-shade grayscale
Alertinfo, warning, error, success, error100Semantic colors
Backgroundbackground14Mapped from neutral shades
TexttextPrimary, textSecondary, textTertiary, textDisabled, textWhite, textHighlightMapped from neutral/primary
IconiconPrimary, iconSecondary, iconTertiary, iconWhite, iconHighlightMapped from neutral/primary
ButtonbuttonBackground, secondaryButtonBackground, buttonText, buttonIconColor, secondaryButtonText, secondaryButtonIconPrimary + neutral
BorderborderLight, borderDefault, borderDark, borderHighlightNeutral shades + primary
Specialwhite, black, messageSeenFixed values

Component Style Classes

Every component has a CometChat{Component}Style class with a merge() method:

CometChatConversations(
  conversationsStyle: CometChatConversationsStyle(
    backgroundColor: colors.background1,
    titleStyle: typography.heading3?.bold,
  ),
)

CometChatMessageList(
  style: CometChatMessageListStyle(
    backgroundColor: colors.background3,
  ),
)

Style classes support merge() for combining defaults with overrides:

final baseStyle = CometChatConversationsStyle(backgroundColor: Colors.white);
final override = CometChatConversationsStyle(titleStyle: myTitleStyle);
final merged = baseStyle.merge(override); // backgroundColor + titleStyle

Theme Caching (Performance-Critical)

Cache theme in didChangeDependencies() — never in build():

class _MyWidgetState extends State<MyWidget> {
  late CometChatColorPalette _colorPalette;
  bool _themeInitialized = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (!_themeInitialized) {
      _colorPalette = CometChatThemeHelper.getColorPalette(context);
      _themeInitialized = true;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(color: _colorPalette.primary); // Cached, no lookup
  }
}

For child widgets that receive theme from parent (hybrid pattern):

class CometChatImageBubble extends StatefulWidget {
  final CometChatColorPalette? colorPalette; // Optional — parent can pass cached value
  // ...
}

class _CometChatImageBubbleState extends State<CometChatImageBubble> {
  late CometChatColorPalette colorPalette;
  bool _themeInitialized = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    if (!_themeInitialized) {
      colorPalette = widget.colorPalette ?? CometChatThemeHelper.getColorPalette(context);
      _themeInitialized = true;
    }
  }

  @override
  void didUpdateWidget(CometChatImageBubble oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.colorPalette != oldWidget.colorPalette && widget.colorPalette != null) {
      colorPalette = widget.colorPalette!;
    }
  }
}

Gotchas

  • CometChatColorPalette is NOT const-constructible. It has mutable default fields (white = Colors.white, black = Colors.black, transparent = Colors.transparent). Writing const CometChatColorPalette(...) or const [CometChatColorPalette()] won't compile.
  • CometChatThemeHelper.getColorPalette(context) does Theme.of(context).extension<CometChatColorPalette>() internally — this is an InheritedWidget lookup. In build() during keyboard animation, this fires every frame causing 44-95ms build times.
  • Extended primary colors are auto-generated by blending primary with white (light) or black (dark). Override individual shades only if the auto-blend doesn't match your brand.
  • CometChatThemeMode.mode is a static field — changing it doesn't trigger rebuilds. You need to also change ThemeData brightness or call setState on the MaterialApp.
  • Style merge() is null-aware: only non-null fields from the override replace the base. This means you can't explicitly set a field to null via merge.

Anti-Patterns

// ❌ WRONG — hardcoded colors
Container(color: Colors.purple)

// ✅ CORRECT — use theme tokens
Container(color: colorPalette.primary)
// ❌ WRONG — theme lookup in build
@override
Widget build(BuildContext context) {
  final colors = CometChatThemeHelper.getColorPalette(context);
  return Text('Hi', style: TextStyle(color: colors.textPrimary));
}

// ❌ ALSO WRONG — theme lookup in a method called from build
Widget _buildProfileMenu() {
  final typography = CometChatThemeHelper.getTypography(context); // Still in build tree!
  final spacing = CometChatThemeHelper.getSpacing(context);
  // ...
}

// ✅ CORRECT — cached in didChangeDependencies
late CometChatColorPalette _colors;
late CometChatTypography _typography;
late CometChatSpacing _spacing;
bool _init = false;
@override
void didChangeDependencies() {
  super.didChangeDependencies();
  if (!_init) {
    _colors = CometChatThemeHelper.getColorPalette(context);
    _typography = CometChatThemeHelper.getTypography(context);
    _spacing = CometChatThemeHelper.getSpacing(context);
    _init = true;
  }
}
@override
Widget build(BuildContext context) {
  return Text('Hi', style: TextStyle(color: _colors.textPrimary));
}
// ❌ WRONG — MediaQuery.of(context).size triggers full rebuild
final size = MediaQuery.of(context).size;

// ✅ CORRECT — only subscribes to size changes
final size = MediaQuery.sizeOf(context);

Checklist

  • [ ] Custom colors registered as ThemeExtension on ThemeData
  • [ ] Both theme and darkTheme configured if supporting dark mode
  • [ ] Theme values cached in didChangeDependencies(), not build()
  • [ ] No CometChatThemeHelper.get*() calls in any method invoked during build() (including helper methods like _buildProfileMenu())
  • [ ] _themeInitialized flag prevents re-init during keyboard animation
  • [ ] No hardcoded colors — all from CometChatColorPalette
  • [ ] MediaQuery.sizeOf(context) used instead of MediaQuery.of(context).size
  • [ ] Style overrides use component's Style class, not inline styles

Related skills

Design & UI/UXuibranding

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.