
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-themingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 70 |
| Last updated | June 23, 2026 |
| Repository | cometchat/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
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.darkColor Palette Tokens
| Category | Tokens | Default Source |
|---|---|---|
| Primary | primary | #6852D6 light / #604CC3 dark |
| Extended Primary | extendedPrimary50–900 | Auto-generated from primary via blend |
| Neutral | neutral50–900 | 10-shade grayscale |
| Alert | info, warning, error, success, error100 | Semantic colors |
| Background | background1–4 | Mapped from neutral shades |
| Text | textPrimary, textSecondary, textTertiary, textDisabled, textWhite, textHighlight | Mapped from neutral/primary |
| Icon | iconPrimary, iconSecondary, iconTertiary, iconWhite, iconHighlight | Mapped from neutral/primary |
| Button | buttonBackground, secondaryButtonBackground, buttonText, buttonIconColor, secondaryButtonText, secondaryButtonIcon | Primary + neutral |
| Border | borderLight, borderDefault, borderDark, borderHighlight | Neutral shades + primary |
| Special | white, black, messageSeen | Fixed 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 + titleStyleTheme 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
CometChatColorPaletteis NOT const-constructible. It has mutable default fields (white = Colors.white,black = Colors.black,transparent = Colors.transparent). Writingconst CometChatColorPalette(...)orconst [CometChatColorPalette()]won't compile.CometChatThemeHelper.getColorPalette(context)doesTheme.of(context).extension<CometChatColorPalette>()internally — this is an InheritedWidget lookup. Inbuild()during keyboard animation, this fires every frame causing 44-95ms build times.- Extended primary colors are auto-generated by blending
primarywith white (light) or black (dark). Override individual shades only if the auto-blend doesn't match your brand. CometChatThemeMode.modeis a static field — changing it doesn't trigger rebuilds. You need to also changeThemeDatabrightness or callsetStateon theMaterialApp.- Style
merge()is null-aware: only non-null fields from the override replace the base. This means you can't explicitly set a field tonullvia 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
ThemeExtensiononThemeData - [ ] Both
themeanddarkThemeconfigured if supporting dark mode - [ ] Theme values cached in
didChangeDependencies(), notbuild() - [ ] No
CometChatThemeHelper.get*()calls in any method invoked duringbuild()(including helper methods like_buildProfileMenu()) - [ ]
_themeInitializedflag prevents re-init during keyboard animation - [ ] No hardcoded colors — all from
CometChatColorPalette - [ ]
MediaQuery.sizeOf(context)used instead ofMediaQuery.of(context).size - [ ] Style overrides use component's Style class, not inline styles