{"id":"b349d8a0-f62c-46de-8610-ca4438b36fd5","shortId":"fCnqPu","kind":"skill","title":"cometchat-flutter-v6-theming","tagline":"Use when customizing the visual appearance of CometChat Flutter UIKit v6 components. Triggers on mentions of CometChatThemeHelper, CometChatColorPalette, CometChatSpacing, CometChatTypography, CometChatThemeMode, dark mode, light mode, theme, colors, styling, custom theme, Style ","description":"# CometChat Flutter UIKit — Theming & Styling\n\nHow to customize the visual appearance of all CometChat components.\n\n## Theme System Architecture\n\nThree layers, resolved via Flutter's `ThemeExtension` system:\n\n1. `CometChatColorPalette` — all colors (primary, neutral, alert, background, text, icon, button, border)\n2. `CometChatSpacing` — spacing tokens\n3. `CometChatTypography` — text styles (heading1-4, body, caption1-2, button, link, title)\n\nAccess via static helpers:\n```dart\nfinal colors = CometChatThemeHelper.getColorPalette(context);\nfinal spacing = CometChatThemeHelper.getSpacing(context);\nfinal typography = CometChatThemeHelper.getTypography(context);\n```\n\n## Applying a Custom Theme\n\nRegister `CometChatColorPalette` as a `ThemeExtension` on your `ThemeData`:\n\n```dart\nMaterialApp(\n  theme: ThemeData(\n    brightness: Brightness.light,\n    extensions: [\n      CometChatColorPalette(\n        primary: const Color(0xFF6852D6),\n        background1: Colors.white,\n        textPrimary: const Color(0xFF141414),\n        // ... override only what you need, rest falls back to defaults\n      ),\n    ],\n  ),\n  darkTheme: ThemeData(\n    brightness: Brightness.dark,\n    extensions: [\n      CometChatColorPalette(\n        primary: const Color(0xFF604CC3),\n        background1: const Color(0xFF141414),\n        textPrimary: Colors.white,\n      ),\n    ],\n  ),\n)\n```\n\nNote: `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.\n\n## Dark Mode\n\n`CometChatThemeMode` controls how brightness is resolved:\n\n```dart\n// Follow system setting (default)\nCometChatThemeMode.mode = ThemeMode.system;\n\n// Force light\nCometChatThemeMode.mode = ThemeMode.light;\n\n// Force dark\nCometChatThemeMode.mode = ThemeMode.dark;\n```\n\nThe helper reads brightness via:\n```dart\n// ThemeMode.system → MediaQuery.of(context).platformBrightness\n// ThemeMode.light → Brightness.light\n// ThemeMode.dark → Brightness.dark\n```\n\n## Color Palette Tokens\n\n| Category | Tokens | Default Source |\n|----------|--------|---------------|\n| Primary | `primary` | `#6852D6` light / `#604CC3` dark |\n| Extended Primary | `extendedPrimary50`–`900` | Auto-generated from primary via blend |\n| Neutral | `neutral50`–`900` | 10-shade grayscale |\n| Alert | `info`, `warning`, `error`, `success`, `error100` | Semantic colors |\n| Background | `background1`–`4` | Mapped from neutral shades |\n| Text | `textPrimary`, `textSecondary`, `textTertiary`, `textDisabled`, `textWhite`, `textHighlight` | Mapped from neutral/primary |\n| Icon | `iconPrimary`, `iconSecondary`, `iconTertiary`, `iconWhite`, `iconHighlight` | Mapped from neutral/primary |\n| Button | `buttonBackground`, `secondaryButtonBackground`, `buttonText`, `buttonIconColor`, `secondaryButtonText`, `secondaryButtonIcon` | Primary + neutral |\n| Border | `borderLight`, `borderDefault`, `borderDark`, `borderHighlight` | Neutral shades + primary |\n| Special | `white`, `black`, `messageSeen` | Fixed values |\n\n## Component Style Classes\n\nEvery component has a `CometChat{Component}Style` class with a `merge()` method:\n\n```dart\nCometChatConversations(\n  conversationsStyle: CometChatConversationsStyle(\n    backgroundColor: colors.background1,\n    titleStyle: typography.heading3?.bold,\n  ),\n)\n\nCometChatMessageList(\n  style: CometChatMessageListStyle(\n    backgroundColor: colors.background3,\n  ),\n)\n```\n\nStyle classes support `merge()` for combining defaults with overrides:\n```dart\nfinal baseStyle = CometChatConversationsStyle(backgroundColor: Colors.white);\nfinal override = CometChatConversationsStyle(titleStyle: myTitleStyle);\nfinal merged = baseStyle.merge(override); // backgroundColor + titleStyle\n```\n\n## Theme Caching (Performance-Critical)\n\nCache theme in `didChangeDependencies()` — never in `build()`:\n\n```dart\nclass _MyWidgetState extends State<MyWidget> {\n  late CometChatColorPalette _colorPalette;\n  bool _themeInitialized = false;\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    if (!_themeInitialized) {\n      _colorPalette = CometChatThemeHelper.getColorPalette(context);\n      _themeInitialized = true;\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Container(color: _colorPalette.primary); // Cached, no lookup\n  }\n}\n```\n\nFor child widgets that receive theme from parent (hybrid pattern):\n```dart\nclass CometChatImageBubble extends StatefulWidget {\n  final CometChatColorPalette? colorPalette; // Optional — parent can pass cached value\n  // ...\n}\n\nclass _CometChatImageBubbleState extends State<CometChatImageBubble> {\n  late CometChatColorPalette colorPalette;\n  bool _themeInitialized = false;\n\n  @override\n  void didChangeDependencies() {\n    super.didChangeDependencies();\n    if (!_themeInitialized) {\n      colorPalette = widget.colorPalette ?? CometChatThemeHelper.getColorPalette(context);\n      _themeInitialized = true;\n    }\n  }\n\n  @override\n  void didUpdateWidget(CometChatImageBubble oldWidget) {\n    super.didUpdateWidget(oldWidget);\n    if (widget.colorPalette != oldWidget.colorPalette && widget.colorPalette != null) {\n      colorPalette = widget.colorPalette!;\n    }\n  }\n}\n```\n\n## Gotchas\n\n- `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.\n- `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.\n- 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.\n- `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`.\n- 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.\n\n## Anti-Patterns\n\n```dart\n// ❌ WRONG — hardcoded colors\nContainer(color: Colors.purple)\n\n// ✅ CORRECT — use theme tokens\nContainer(color: colorPalette.primary)\n```\n\n```dart\n// ❌ WRONG — theme lookup in build\n@override\nWidget build(BuildContext context) {\n  final colors = CometChatThemeHelper.getColorPalette(context);\n  return Text('Hi', style: TextStyle(color: colors.textPrimary));\n}\n\n// ❌ ALSO WRONG — theme lookup in a method called from build\nWidget _buildProfileMenu() {\n  final typography = CometChatThemeHelper.getTypography(context); // Still in build tree!\n  final spacing = CometChatThemeHelper.getSpacing(context);\n  // ...\n}\n\n// ✅ CORRECT — cached in didChangeDependencies\nlate CometChatColorPalette _colors;\nlate CometChatTypography _typography;\nlate CometChatSpacing _spacing;\nbool _init = false;\n@override\nvoid didChangeDependencies() {\n  super.didChangeDependencies();\n  if (!_init) {\n    _colors = CometChatThemeHelper.getColorPalette(context);\n    _typography = CometChatThemeHelper.getTypography(context);\n    _spacing = CometChatThemeHelper.getSpacing(context);\n    _init = true;\n  }\n}\n@override\nWidget build(BuildContext context) {\n  return Text('Hi', style: TextStyle(color: _colors.textPrimary));\n}\n```\n\n```dart\n// ❌ WRONG — MediaQuery.of(context).size triggers full rebuild\nfinal size = MediaQuery.of(context).size;\n\n// ✅ CORRECT — only subscribes to size changes\nfinal size = MediaQuery.sizeOf(context);\n```\n\n## Checklist\n\n- [ ] Custom colors registered as `ThemeExtension` on `ThemeData`\n- [ ] Both `theme` and `darkTheme` configured if supporting dark mode\n- [ ] Theme values cached in `didChangeDependencies()`, not `build()`\n- [ ] No `CometChatThemeHelper.get*()` calls in any method invoked during `build()` (including helper methods like `_buildProfileMenu()`)\n- [ ] `_themeInitialized` flag prevents re-init during keyboard animation\n- [ ] No hardcoded colors — all from `CometChatColorPalette`\n- [ ] `MediaQuery.sizeOf(context)` used instead of `MediaQuery.of(context).size`\n- [ ] Style overrides use component's Style class, not inline styles","tags":["cometchat","flutter","theming","skills","agent-skills","ai-agent","chat","claude-code","cursor","messaging","nextjs","react"],"capabilities":["skill","source-cometchat","skill-cometchat-flutter-v6-theming","topic-agent-skills","topic-ai-agent","topic-chat","topic-claude-code","topic-cometchat","topic-cursor","topic-messaging","topic-nextjs","topic-react","topic-react-native","topic-ui-kit"],"categories":["cometchat-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cometchat/cometchat-skills/cometchat-flutter-v6-theming","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cometchat/cometchat-skills","source_repo":"https://github.com/cometchat/cometchat-skills","install_from":"skills.sh"}},"qualityScore":"0.463","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 27 github stars · SKILL.md body (8,348 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:04:52.288Z","embedding":null,"createdAt":"2026-05-07T13:05:12.065Z","updatedAt":"2026-05-18T19:04:52.288Z","lastSeenAt":"2026-05-18T19:04:52.288Z","tsv":"'-2':87 '-4':84 '-95':525 '0xff141414':137,161 '0xff604cc3':157 '0xff6852d6':131 '1':63 '10':254 '2':75 '3':79 '4':267 '44':524 '604cc3':238 '6852d6':236 '900':243,253 'access':91 'alert':69,257 'also':573,652 'anim':518,790 'anti':614 'anti-pattern':613 'appear':11,47 'appli':108 'architectur':54 'auto':245,534,552 'auto-blend':551 'auto-gener':244,533 'awar':588 'back':145 'background':70,265 'background1':132,158,266 'backgroundcolor':333,341,356,367 'base':599 'basestyl':354 'basestyle.merge':365 'black':179,310,489,543 'blend':250,537,553 'bodi':85 'bold':337 'bool':389,446,689 'border':74,300 'borderdark':303 'borderdefault':302 'borderhighlight':304 'borderlight':301 'brand':558 'bright':124,150,195,216,576 'brightness.dark':151,226 'brightness.light':125,224 'build':380,405,515,527,635,638,661,670,711,767,776 'buildcontext':406,639,712 'buildprofilemenu':663,781 'button':73,88,291 'buttonbackground':292 'buttoniconcolor':295 'buttontext':294 'cach':370,374,412,437,677,763 'call':578,659,770 'caption1':86 'categori':230 'caus':523 'chang':564,574,739 'checklist':744 'child':416 'class':316,324,344,382,426,439,811 'color':32,66,97,130,136,156,160,227,264,410,531,619,621,628,642,650,682,698,719,746,793 'colorpalett':388,398,432,445,455,473 'colorpalette.primary':411,629 'colors.background1':334 'colors.background3':342 'colors.black':490 'colors.purple':622 'colors.textprimary':651,720 'colors.transparent':492 'colors.white':133,163,357,488 'combin':348 'cometchat':2,13,37,50,321 'cometchat-flutter-v6-theming':1 'cometchatcolorpalett':23,64,113,127,153,165,185,387,431,444,476,495,498,681,796 'cometchatconvers':330 'cometchatconversationsstyl':332,355,360 'cometchatimagebubbl':427,464 'cometchatimagebubblest':440 'cometchatmessagelist':338 'cometchatmessageliststyl':340 'cometchatspac':24,76,687 'cometchatthemehelp':22 'cometchatthemehelper.get':769 'cometchatthemehelper.getcolorpalette':98,399,457,502,643,699 'cometchatthemehelper.getspacing':102,674,705 'cometchatthemehelper.gettypography':106,666,702 'cometchatthememod':26,192 'cometchatthememode.mode':203,207,211,559 'cometchattypographi':25,80,684 'compil':189,501 'compon':17,51,314,318,322,808 'configur':756 'const':129,135,155,159,170,184,480,494,497 'const-construct':479 'construct':481 'constructor':171 'contain':409,620,627 'context':99,103,107,221,400,407,458,503,506,640,644,667,675,700,703,706,713,724,732,743,798,803 'control':193 'conversationsstyl':331 'correct':623,676,734 'critic':373 'custom':8,34,44,110,745 'dark':27,190,210,239,544,759 'darkthem':148,755 'dart':95,120,198,218,329,352,381,425,616,630,721 'default':147,175,202,232,349,485 'didchangedepend':377,394,451,679,694,765 'didupdatewidget':463 'doesn':554,566 'error':260 'error100':262 'everi':317,521 'explicit':605 'extend':240,384,428,441,529 'extendedprimary50':242 'extens':126,152,507 'fall':144 'fals':391,448,691 'field':176,486,563,593,608 'final':96,100,104,353,358,363,430,641,664,672,729,740 'fire':520 'fix':312 'flag':783 'flutter':3,14,38,59 'follow':199 'forc':205,209 'frame':522 'full':727 'generat':246,535 'gotcha':475 'grayscal':256 'hardcod':618,792 'heading1':83 'helper':94,214,778 'hi':647,716 'hybrid':423 'icon':72,282 'iconhighlight':287 'iconprimari':283 'iconsecondari':284 'icontertiari':285 'iconwhit':286 'includ':777 'individu':546 'info':258 'inheritedwidget':512 'init':690,697,707,787 'inlin':813 'instead':800 'intern':508 'invok':774 'keyboard':517,789 'late':386,443,680,683,686 'layer':56 'light':29,206,237,541 'like':780 'link':89 'lookup':414,513,633,655 'map':268,279,288 'match':556 'materialapp':121,582 'mean':601 'mediaquery.of':220,723,731,802 'mediaquery.sizeof':742,797 'mention':20 'merg':327,346,364,584,612 'messageseen':311 'method':328,658,773,779 'mode':28,30,191,760 'ms':526 'mutabl':174,484 'mytitlestyl':362 'mywidgetst':383 'need':142,571 'neutral':68,251,270,299,305 'neutral/primary':281,290 'neutral50':252 'never':378 'non':591 'non-nul':590 'note':164 'null':472,587,592,610 'null-awar':586 'oldwidget':465,467 'oldwidget.colorpalette':470 'option':433 'overrid':138,351,359,366,392,403,449,461,545,596,636,692,709,806 'palett':228 'parent':422,434 'pass':436 'pattern':424,615 'perform':372 'performance-crit':371 'platformbright':222 'prevent':784 'primari':67,128,154,234,235,241,248,298,307,530,538 're':786 're-init':785 'read':215 'rebuild':569,728 'receiv':419 'regist':112,747 'replac':597 'resolv':57,197 'rest':143 'return':408,645,714 'secondarybuttonbackground':293 'secondarybuttonicon':297 'secondarybuttontext':296 'semant':263 'set':201,606 'setstat':579 'shade':255,271,306,547 'size':725,730,733,738,741,804 'skill' 'skill-cometchat-flutter-v6-theming' 'sourc':233 'source-cometchat' 'space':77,101,673,688,704 'special':308 'state':385,442 'statefulwidget':429 'static':93,562 'still':668 'style':33,36,41,82,315,323,339,343,583,648,717,805,810,814 'subscrib':736 'success':261 'super.didchangedependencies':395,452,695 'super.didupdatewidget':466 'support':345,758 'system':53,62,200 'text':71,81,272,646,715 'textdis':276 'texthighlight':278 'textprimari':134,162,273 'textsecondari':274 'textstyl':649,718 'texttertiari':275 'textwhit':277 'theme':5,31,35,40,52,111,122,369,375,420,625,632,654,753,761 'theme.of':505 'themedata':119,123,149,575,751 'themeextens':61,116,749 'themeiniti':390,397,401,447,454,459,782 'thememode.dark':212,225 'thememode.light':208,223 'thememode.system':204,219 'three':55 'time':528 'titl':90 'titlestyl':335,361,368 'token':78,229,231,626 'topic-agent-skills' 'topic-ai-agent' 'topic-chat' 'topic-claude-code' 'topic-cometchat' 'topic-cursor' 'topic-messaging' 'topic-nextjs' 'topic-react' 'topic-react-native' 'topic-ui-kit' 'transpar':180,491 'tree':671 'tri':183 'trigger':18,568,726 'true':402,460,708 'typographi':105,665,685,701 'typography.heading3':336 'uikit':15,39 'use':6,624,799,807 'v6':4,16 'valu':313,438,762 'via':58,92,217,249,611 'visual':10,46 'void':393,450,462,693 'warn':259 'white':178,309,487,540 'widget':404,417,637,662,710 'widget.colorpalette':456,469,471,474 'won':187,499 'write':493 'wrong':617,631,653,722","prices":[{"id":"a95296b8-118d-43af-8544-cbab913bdbad","listingId":"b349d8a0-f62c-46de-8610-ca4438b36fd5","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cometchat","category":"cometchat-skills","install_from":"skills.sh"},"createdAt":"2026-05-07T13:05:12.065Z"}],"sources":[{"listingId":"b349d8a0-f62c-46de-8610-ca4438b36fd5","source":"github","sourceId":"cometchat/cometchat-skills/cometchat-flutter-v6-theming","sourceUrl":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-flutter-v6-theming","isPrimary":false,"firstSeenAt":"2026-05-07T13:05:12.065Z","lastSeenAt":"2026-05-18T19:04:52.288Z"}],"details":{"listingId":"b349d8a0-f62c-46de-8610-ca4438b36fd5","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cometchat","slug":"cometchat-flutter-v6-theming","github":{"repo":"cometchat/cometchat-skills","stars":27,"topics":["agent-skills","ai-agent","chat","claude-code","cometchat","cursor","messaging","nextjs","react","react-native","ui-kit"],"license":null,"html_url":"https://github.com/cometchat/cometchat-skills","pushed_at":"2026-05-18T05:04:24Z","description":"Add CometChat chat to any React, Next.js, React Native, Angular, Android, iOS, or Flutter project through your AI coding agent. Works with Claude Code, Cursor, Codex, VS Code Copilot, Windsurf, Cline, Kiro, and 50+ more agents.","skill_md_sha":"5749bc19c46f882f4d6d9f027ce3493f41b246a9","skill_md_path":"skills/cometchat-flutter-v6-theming/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cometchat/cometchat-skills/tree/main/skills/cometchat-flutter-v6-theming"},"layout":"multi","source":"github","category":"cometchat-skills","frontmatter":{"name":"cometchat-flutter-v6-theming","license":"MIT","description":"Use when customizing the visual appearance of CometChat Flutter UIKit v6 components. Triggers on mentions of CometChatThemeHelper, CometChatColorPalette, CometChatSpacing, CometChatTypography, CometChatThemeMode, dark mode, light mode, theme, colors, styling, custom theme, Style class, merge(), getColorPalette, getSpacing, getTypography, ThemeExtension, primary color, neutral colors, background colors, text colors, icon colors, button colors, border colors, or any CometChat{Component}Style class. Also use when the user asks about changing colors, fonts, spacing, or appearance of chat components.","compatibility":"cometchat_chat_uikit ^6.0.0-beta2; flutter >=2.5.0"},"skills_sh_url":"https://skills.sh/cometchat/cometchat-skills/cometchat-flutter-v6-theming"},"updatedAt":"2026-05-18T19:04:52.288Z"}}