igniteui-cli 15.1.0 → 15.2.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/lib/PromptSession.d.ts +1 -1
  2. package/lib/PromptSession.js +2 -2
  3. package/lib/commands/ai-config.d.ts +3 -5
  4. package/lib/commands/ai-config.js +68 -23
  5. package/lib/commands/new.js +1 -1
  6. package/package.json +4 -4
  7. package/templates/blazor/igb/index.d.ts +1 -0
  8. package/templates/blazor/igb/index.js +12 -0
  9. package/templates/blazor/igb/projects/ai-config/files/AGENTS.md +65 -0
  10. package/templates/blazor/igb/projects/ai-config/files/skills/AGENTS.md +65 -0
  11. package/templates/blazor/igb/projects/ai-config/files/skills/README.md +61 -0
  12. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/SKILL.md +118 -0
  13. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/charts.md +302 -0
  14. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/data-display.md +350 -0
  15. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/feedback.md +178 -0
  16. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/form-controls.md +365 -0
  17. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/layout-manager.md +180 -0
  18. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/layout.md +322 -0
  19. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/mcp-setup.md +78 -0
  20. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-components/references/setup.md +214 -0
  21. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-generate-from-image-design/SKILL.md +284 -0
  22. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-generate-from-image-design/references/component-mapping.md +281 -0
  23. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-generate-from-image-design/references/gotchas.md +503 -0
  24. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/SKILL.md +188 -0
  25. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/data-operations.md +264 -0
  26. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/editing.md +297 -0
  27. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/features.md +447 -0
  28. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/mcp-setup.md +78 -0
  29. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/paging-remote.md +299 -0
  30. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/sizing.md +284 -0
  31. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/state.md +160 -0
  32. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/structure.md +497 -0
  33. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-grids/references/types.md +553 -0
  34. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-theming/SKILL.md +259 -0
  35. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-theming/references/common-patterns.md +276 -0
  36. package/templates/blazor/igb/projects/ai-config/files/skills/igniteui-blazor-theming/references/mcp-setup.md +81 -0
  37. package/templates/blazor/igb/projects/ai-config/index.d.ts +22 -0
  38. package/templates/blazor/igb/projects/ai-config/index.js +62 -0
  39. package/templates/blazor/index.d.ts +3 -0
  40. package/templates/blazor/index.js +11 -0
@@ -0,0 +1,503 @@
1
+ # Ignite UI Blazor Gotchas & Pitfalls
2
+
3
+ ## Table of Contents
4
+ - [CSS Isolation & Scoping](#css-isolation--scoping)
5
+ - [Chart Properties](#chart-properties)
6
+ - [Component Properties](#component-properties)
7
+ - [Theming Pitfalls](#theming-pitfalls)
8
+ - [Map Component](#map-component)
9
+ - [Dark Theme Specifics](#dark-theme-specifics)
10
+ - [Blazor-specific Gotchas](#blazor-specific-gotchas)
11
+
12
+ ---
13
+
14
+ ## CSS Isolation & Scoping
15
+
16
+ Ignite UI for Blazor components render as web components (`igc-chip`, `igc-grid`, etc.). Use three CSS mechanisms depending on what you need and where the CSS lives:
17
+
18
+ | Mechanism | Purpose | Priority |
19
+ |---|---|---|
20
+ | Design tokens `--ig-*` | Override colors, borders, shadows via CSS vars | **Primary** - use whenever a token exists |
21
+ | `::part()` | Target a named shadow DOM part directly | **Secondary** - only when no token covers it; confirm part names via `get_doc` |
22
+ | `::deep` | Pierce Blazor CSS isolation in `.razor.css` files | **File helper** - add it in `.razor.css`; never needed in global CSS |
23
+
24
+ `::deep` and `::part()` solve different problems and are often combined: `::deep igc-chip::part(base) { ... }`.
25
+
26
+ **`::deep` applies only to `igc-*` selectors - never to plain HTML or CSS class selectors.**
27
+
28
+ `::deep` is not a general-purpose CSS scope piercer. It only works when Blazor's scope attribute is present on a parent element above the targeted element in the DOM. This means:
29
+
30
+ - **DO** use `::deep` for `igc-*` element selectors and `igc-*::part()` combinations in `.razor.css` files.
31
+ - **DO NOT** use `::deep` for plain HTML class selectors. These are already scoped by Blazor's CSS isolation and work without `::deep`.
32
+ - **DO NOT** use `::deep` to target the root element of a component - Blazor places the scope attribute on the root element itself, so there is no scoped parent above it to make `::deep` work. Style the root element with a plain class selector.
33
+
34
+ **Global CSS (`app.css`)** - write selectors directly:
35
+ ```css
36
+ igc-chip { --ig-chip-background: var(--ig-primary-500); }
37
+ igc-dialog::part(footer) { border-top: 1px solid var(--ig-gray-200); }
38
+ ```
39
+
40
+ **`.razor.css` isolation file** - prefix `igc-*` selectors with `::deep`; write plain HTML class selectors without it:
41
+ ```css
42
+ ::deep igc-chip { --ig-chip-background: var(--ig-primary-500); }
43
+ ::deep igc-dialog::part(footer) { border-top: 1px solid var(--ig-gray-200); }
44
+
45
+ .class-selector { display: grid; grid-template-columns: 260px 1fr; }
46
+ ```
47
+
48
+ `create_component_theme(platform: "blazor", output: "css")` generates global CSS selectors - use as-is in `app.css`, or add `::deep` when placing in a `.razor.css` file. Never add `::deep` to `:root {}` blocks or plain HTML class rules.
49
+
50
+ Blazor projects do **not** use Sass/SCSS.
51
+
52
+ ---
53
+
54
+ ## Chart Properties
55
+
56
+ ### Markers shown by default
57
+ Category charts show markers at every data point by default. If the screenshot does not show markers, set `MarkerTypes` using the documented pattern for the installed version. When setting it from code, add the enum value after the chart reference is ready:
58
+ ```razor
59
+ <IgbCategoryChart @ref="chart" ... />
60
+
61
+ @code {
62
+ private IgbCategoryChart chart = default!;
63
+
64
+ protected override void OnAfterRender(bool firstRender)
65
+ {
66
+ if (firstRender)
67
+ {
68
+ chart.MarkerTypes.Add(MarkerType.None);
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ ### Charts do NOT inherit CSS theme colors
75
+ Charts, maps, gauges, and sparklines ignore the global CSS custom property theme. Set their visual properties explicitly via component parameters:
76
+ ```razor
77
+ <IgbCategoryChart
78
+ Brushes="#4FC3F7 #81C784 #FFB74D"
79
+ Outlines="#4FC3F7 #81C784 #FFB74D"
80
+ MarkerBrushes="#4FC3F7 #81C784 #FFB74D"
81
+ MarkerOutlines="#4FC3F7 #81C784 #FFB74D"
82
+ XAxisLabelTextColor="#666666"
83
+ YAxisLabelTextColor="#666666" />
84
+ ```
85
+
86
+ After a palette exists, prefer referencing palette tokens via `var(--ig-primary-500)` where the component supports CSS custom properties, or resolve the actual color value from the palette for DV component parameters.
87
+
88
+ ### `Brushes`, `Outlines`, `MarkerBrushes`, `MarkerOutlines` are brush-list strings
89
+ These are **string** parameters, not arrays. Pass colors as a single string separated by spaces.
90
+ ```razor
91
+ Brushes="#FF6B6B #4ECDC4 #45B7D1"
92
+ ```
93
+
94
+ ### `AreaFillOpacity` exists on `IgbCategoryChart`
95
+ It does **NOT** exist on `IgbSparkline`. For sparkline fill, use the `Brush` parameter.
96
+
97
+ ### `IgbSparkline` has no SplineArea type — use `IgbCategoryChart` for smooth area sparklines
98
+ `IgbSparkline` supports only `Line`, `Area`, `Column`, and `WinLoss` display types. `Area` renders as angular polygon fills, not smooth curves. If the design shows smooth mountain-shaped area sparklines, use a small `IgbCategoryChart` with `ChartType="CategoryChartType.SplineArea"`:
99
+
100
+ ```razor
101
+ <!-- ❌ Angular fill — no smooth curves available on IgbSparkline -->
102
+ <IgbSparkline DisplayType="SparklineDisplayType.Area" Brush="#5B57E8" ... />
103
+
104
+ <!-- ✅ Smooth spline area sparkline -->
105
+ <IgbCategoryChart @ref="splineChart"
106
+ ChartType="@CategoryChartType.SplineArea"
107
+ Brushes="#5B57E8"
108
+ Outlines="#5B57E8"
109
+ AreaFillOpacity="0.35"
110
+ XAxisLabelTextColor="transparent"
111
+ YAxisLabelTextColor="transparent"
112
+ Height="70px"
113
+ Width="100%"
114
+ DataSource="@SparkData" />
115
+ ```
116
+
117
+
118
+ ### `IncludedProperties` and `ExcludedProperties` are string arrays
119
+ Pass them as bound parameters:
120
+ ```razor
121
+ <IgbCategoryChart IncludedProperties='@(new string[] { "Month", "Revenue" })' ... />
122
+ ```
123
+
124
+ ### `InnerExtent` is a chart-level property — never a series-level property
125
+
126
+ `InnerExtent` controls the hole size at the center of a donut/pie chart. It is a property of the **chart** component (`IgbDoughnutChart`, `IgbPieChart`, `IgbDataPieChart`), not of any series child. Placing it on `IgbRingSeries` causes a runtime crash:
127
+
128
+ ```
129
+ System.InvalidOperationException: IgbRingSeries does not have a property matching 'InnerExtent'
130
+ ```
131
+
132
+ Correct usage:
133
+ ```razor
134
+ <!-- ✅ InnerExtent on the chart -->
135
+ <IgbDoughnutChart InnerExtent="0.45" Width="220px" Height="220px">
136
+ <IgbRingSeries ValueMemberPath="Value" LabelMemberPath="Label" ... />
137
+ </IgbDoughnutChart>
138
+
139
+ <!-- ❌ Runtime crash -->
140
+ <IgbRingSeries InnerExtent="0.45" ... />
141
+ ```
142
+
143
+ ### Set `Brushes`, `Outlines`, and visual parameters inline — not via `@ref` in `OnAfterRenderAsync`
144
+
145
+ Setting visual parameters via `@ref` property assignment in `OnAfterRenderAsync` triggers Blazor warning **BL0005** (*Component parameter should not be set outside of its component*). Always pass them as **inline Razor markup attributes** instead.
146
+
147
+ ```razor
148
+ <!-- ✅ Inline markup — no BL0005 -->
149
+ <IgbRingSeries Brushes="#CF6E7A #6C74DC #D4A84B" Outlines="#13131F #13131F #13131F" ... />
150
+
151
+ <!-- ❌ BL0005 warning -->
152
+ jobSeries.Brushes = "#CF6E7A #6C74DC #D4A84B";
153
+ ```
154
+
155
+ ### Smooth area/line charts
156
+ Match `ChartType` to the curve shape in the screenshot:
157
+ - Smooth flowing curves → `Spline` (lines) or `SplineArea` (filled)
158
+ - Angular/jagged lines → `Line` or `Area`
159
+ - Step-shaped → `StepLine` or `StepArea`
160
+
161
+ Do not default to `Line` or `Area` when the screenshot shows smooth curves. The difference is immediately visible and is the most common chart fidelity mistake.
162
+
163
+ ### Circular ring with centered percentage — choosing the right component
164
+ - **Thick static ring with a centred label and no needle** → `IgbDoughnutChart` + `IgbRingSeries`. Place `InnerExtent` on the chart, not the series. Overlay the label with `position: absolute` inside a `position: relative` wrapper.
165
+ - **Thin animated spinner / loading progress** → `IgbCircularProgress`. Not a data visualisation.
166
+ - **Needle pointer on a scale arc** → `IgbRadialGauge`.
167
+
168
+ `IgbRadialGauge` and `IgbCircularProgress` will never produce a clean static ring. Use `IgbDoughnutChart` whenever the design shows a coloured arc ring with a centred value and no needle.
169
+
170
+ ```razor
171
+ <div class="gauge-wrapper">
172
+ <IgbDoughnutChart InnerExtent="0.62" Height="160px" Width="160px" AllowSliceExplosion="false">
173
+ <IgbRingSeries ValueMemberPath="Value" LabelMemberPath="Category"
174
+ LabelsPosition="@LabelsPosition.None"
175
+ DataSource="@GaugeData"
176
+ Brushes="#5B57E8 #e8e8f5"
177
+ Outlines="transparent transparent"
178
+ RadiusFactor="0.95" />
179
+ </IgbDoughnutChart>
180
+ <div class="gauge-label">75%</div>
181
+ </div>
182
+ ```
183
+
184
+ ```css
185
+ .gauge-wrapper { position: relative; display: inline-flex; align-items: center; justify-content: center; }
186
+ .gauge-label { position: absolute; font-size: 1.9rem; font-weight: 700; }
187
+ ```
188
+
189
+ ### Charts inside CSS Grid can collapse
190
+ Charts may render with zero height inside a CSS Grid container. Set `min-height: 0` on the grid cell and `Height="100%"` on the chart component so the chart fills its container without requiring a fixed pixel value:
191
+ ```css
192
+ .chart-container {
193
+ min-height: 0; /* Prevents the CSS Grid track from collapsing */
194
+ }
195
+ ```
196
+ ```razor
197
+ <IgbCategoryChart Height="100%" Width="100%" ... />
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Component Properties
203
+
204
+ ### IgbAvatar: use `Shape` parameter
205
+ Use the `Shape` parameter with `AvatarShape.Circle`, `AvatarShape.Rounded`, or `AvatarShape.Square`. There is no `RoundShape` property:
206
+ ```razor
207
+ <IgbAvatar Shape="AvatarShape.Circle" Initials="JD" />
208
+ ```
209
+
210
+ ### Icons in web component slots: use IgbIcon, not font-icon spans
211
+
212
+ Always use `IgbIcon` in slots (`prefix`, `suffix`, `start`, `end`, `icon`). `<span class="material-icons">` is `display: inline` - `vertical-align` is ignored by the slot's flex container, so the icon drifts to the top. `IgbIcon` is `display: inline-flex; align-items: center` and self-centers automatically.
213
+
214
+ ```razor
215
+ <!-- ❌ icon drifts to top -->
216
+ <IgbInput><span slot="prefix" class="material-icons">search</span></IgbInput>
217
+
218
+ <!-- ✅ self-centering -->
219
+ <IgbInput><IgbIcon @ref="_icon" slot="prefix" IconName="search" Collection="material" /></IgbInput>
220
+ ```
221
+ Register the icon in `OnAfterRenderAsync(firstRender)` after `EnsureReady()`.
222
+
223
+ ### IgbList: slot-based structure
224
+ Use named `slot` attributes on child elements inside `IgbListItem` for positioning:
225
+ ```razor
226
+ <IgbListItem>
227
+ <IgbAvatar slot="start" Shape="AvatarShape.Circle" Initials="AB" />
228
+ <span slot="title">Item Title</span>
229
+ <span slot="subtitle">Secondary text</span>
230
+ <IgbIcon slot="end" Collection="material" IconName="chevron_right" />
231
+ </IgbListItem>
232
+ ```
233
+
234
+ ### IgbNavDrawer:
235
+ The component's `::part(base)` is always `position: fixed; transform: translateX(-Npx)` - the host contributes `width: 0` to the layout. `Open="true"` makes it visible but still floating over content. `slot="mini"` adds a collapsed icon-only state. There is no `pin`/`pinned` Blazor parameter.
236
+
237
+ To make the drawer occupy real layout space (pinned sidebar), override the parts in **global CSS**: set explicit width on the host, `position: relative; transform: none` on `::part(base)`, hide `::part(overlay)`, and strip `inert` from `::part(base)` via JS in `OnAfterRenderAsync`. See `layout.md` for the full pattern.
238
+
239
+ ### IgbTileManager: drag and resize modes
240
+ Set `DragMode` and `ResizeMode` for interactive dashboards:
241
+ ```razor
242
+ <IgbTileManager DragMode="TileManagerDragMode.TileHeader" ResizeMode="TileManagerResizeMode.Always">
243
+ <IgbTile ColSpan="2" RowSpan="1">...</IgbTile>
244
+ </IgbTileManager>
245
+ ```
246
+
247
+ Valid drag modes include `TileHeader`, `Tile`, and `None`. Valid resize modes include `Always`, `Hover`, and `None`.
248
+
249
+ ### IgbGrid: virtual rendering
250
+ The grid requires a container with a defined height. Without it, the grid will not virtualize and may render all rows:
251
+ ```css
252
+ ::deep igc-grid {
253
+ height: 500px;
254
+ }
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Theming Pitfalls
260
+
261
+ ### DV components do NOT inherit CSS theme colors
262
+ Charts, maps, gauges, and sparklines ignore the global CSS custom property theme entirely. Set their visual properties explicitly via component parameters. After a palette exists, use the resolved color values (not `var()` references) for DV component parameters:
263
+ ```razor
264
+ <IgbCategoryChart
265
+ Brushes="@primaryColor"
266
+ Outlines="@primaryColor"
267
+ XAxisLabelTextColor="@grayColor"
268
+ YAxisMajorStroke="@grayLightColor" />
269
+ ```
270
+
271
+ ### Component-scoped theme overrides
272
+ For core UI component theming, use `create_component_theme` with `platform: "blazor"` and `output: "css"`. The MCP generates global CSS selectors (`igc-*`). Place the output in:
273
+
274
+ - **Global `app.css`** - use as-is (no `::deep`).
275
+ - **`.razor.css` isolation file** - add `::deep` to each selector:
276
+
277
+ ```css
278
+ /* Dashboard.razor.css - add ::deep for isolation file */
279
+ ::deep igc-grid {
280
+ --ig-grid-header-background: var(--ig-primary-100);
281
+ --ig-grid-content-background: var(--ig-surface-500);
282
+ }
283
+ ```
284
+
285
+ Use `::part()` on an `igc-*` selector only when the property you need is not covered by any design token (verify via `get_component_design_tokens` first). In isolation files, combine `::deep` with `::part()`:
286
+
287
+ ```css
288
+ /* MyView.razor.css */
289
+ ::deep igc-dialog::part(footer) {
290
+ border-top: 1px solid var(--ig-gray-200);
291
+ }
292
+ ```
293
+
294
+ ### Nav drawer sizing
295
+ Size the drawer with layout CSS around the drawer or with CSS parts/tokens verified from the current docs.
296
+ ```css
297
+ .shell {
298
+ display: grid;
299
+ grid-template-columns: 260px 1fr;
300
+ }
301
+ ```
302
+
303
+ ### Dark theme overrides for grids
304
+ In dark themes, grid headers and rows may need explicit background overrides to match the design's surface hierarchy:
305
+ ```css
306
+ ::deep igc-grid {
307
+ --ig-grid-header-background: var(--ig-surface-500);
308
+ --ig-grid-content-background: var(--ig-surface-500);
309
+ --ig-grid-row-hover-background: var(--ig-gray-100);
310
+ }
311
+ ```
312
+
313
+ ### No hardcoded colors after palette generation
314
+ Once a palette has been defined (via CSS custom property overrides or MCP `create_palette` / `create_theme`), core UI component colors should come from generated palette tokens - do not hardcode hex/RGB/HSL values. DV component parameters are the exception: charts, maps, gauges, and sparklines often need resolved color strings because they do not consume CSS variables consistently.
315
+
316
+ **WRONG** (hardcoded hex - breaks theme switching, ignores the palette):
317
+ ```css
318
+ /* app.css - global */
319
+ igc-avatar {
320
+ --ig-avatar-background: #e91e63;
321
+ }
322
+ ```
323
+
324
+ **RIGHT** (palette token - stays in sync with the theme):
325
+ ```css
326
+ /* app.css - global */
327
+ igc-avatar {
328
+ --ig-avatar-background: var(--ig-primary-500);
329
+ --ig-avatar-color: var(--ig-primary-500-contrast);
330
+ }
331
+
332
+ /* MyView.razor.css - isolation file: same tokens, add ::deep */
333
+ ::deep igc-avatar {
334
+ --ig-avatar-background: var(--ig-primary-500);
335
+ --ig-avatar-color: var(--ig-primary-500-contrast);
336
+ }
337
+ ```
338
+
339
+ ### Read luminance warnings from theme generation
340
+ If `create_theme` returns a luminance warning for a generated surface, do not ignore it. If the design needs multiple surface depths, use `create_custom_palette` or define semantic CSS variables such as `--surface-1` and `--surface-2` in the global CSS file instead of relying on a single generated surface color.
341
+
342
+ ---
343
+
344
+ ## Map Component
345
+
346
+ ### Adding markers programmatically
347
+ Map series are added as child components in Razor markup, not programmatically:
348
+ ```razor
349
+ <IgbGeographicMap Height="500px" Width="100%">
350
+ <IgbGeographicSymbolSeries
351
+ DataSource="Locations"
352
+ LatitudeMemberPath="Lat"
353
+ LongitudeMemberPath="Lon"
354
+ MarkerType="MarkerType.Circle"
355
+ MarkerBrush="#FF5722" />
356
+ </IgbGeographicMap>
357
+ ```
358
+
359
+ ### Dark map styling
360
+ OpenStreetMap tiles are light by default. For dark themes, apply a CSS filter to the map container. Adjust the values to match the map tone in the design image:
361
+ ```css
362
+ .map-container {
363
+ /* tune grayscale (0-1) and brightness (0-1) to match the design */
364
+ filter: grayscale(0.8) brightness(0.6);
365
+ }
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Dark Theme Specifics
371
+
372
+ ### Use the dark theme CSS variant
373
+ Switch the theme `<link>` from light to dark:
374
+ ```html
375
+ <!-- Light -->
376
+ <link href="_content/IgniteUI.Blazor/themes/light/bootstrap.css" rel="stylesheet" />
377
+ <!-- Dark -->
378
+ <link href="_content/IgniteUI.Blazor/themes/dark/bootstrap.css" rel="stylesheet" />
379
+ ```
380
+
381
+ ### CSS custom properties for dark panels
382
+ When the design has multiple dark surface depths (e.g., sidebar darker than content area), define semantic tokens:
383
+ ```css
384
+ :root {
385
+ --surface-1: var(--ig-gray-900); /* deepest (sidebar, drawer) */
386
+ --surface-2: var(--ig-gray-800); /* content area */
387
+ --surface-3: var(--ig-gray-700); /* elevated cards/panels */
388
+ }
389
+ ```
390
+
391
+ Apply these in layout CSS rather than hardcoding hex values.
392
+
393
+ ### Programmatic dark/light toggle
394
+ Swap the CSS `<link>` element via JS interop:
395
+ ```html
396
+ <script>
397
+ window.themeSwitcher = {
398
+ setTheme(href) {
399
+ document.getElementById('theme-css').href = href;
400
+ }
401
+ };
402
+ </script>
403
+ ```
404
+
405
+ ```csharp
406
+ await JS.InvokeVoidAsync(
407
+ "themeSwitcher.setTheme",
408
+ "_content/IgniteUI.Blazor/themes/dark/bootstrap.css");
409
+ ```
410
+
411
+ Or toggle a CSS class with variable overrides (see `igniteui-blazor-theming` skill for full patterns).
412
+
413
+ ---
414
+
415
+ ## Blazor-specific Gotchas
416
+
417
+ ### Always register modules in `Program.cs`
418
+ Every `Igb*` component needs its `IgbXxxModule` registered via `AddIgniteUIBlazor()`. If a component silently fails to render, the most common cause is a missing module registration:
419
+ ```csharp
420
+ builder.Services.AddIgniteUIBlazor(
421
+ typeof(IgbCategoryChartModule),
422
+ typeof(IgbListModule),
423
+ typeof(IgbNavbarModule)
424
+ );
425
+ ```
426
+
427
+ ### Two-way binding uses `@bind-` prefix where the component exposes bindable values
428
+ Blazor uses `@bind-Value`, `@bind-Checked`, etc. Verify the exact bindable parameter from the component docs before inventing one:
429
+ ```razor
430
+ <IgbInput @bind-Value="searchText" />
431
+ <IgbSwitch @bind-Checked="isDarkMode" />
432
+ ```
433
+
434
+ ### Event handler pattern
435
+ Use the event pattern shown in the Blazor docs for that component. Native click handling on Ignite UI buttons commonly uses Blazor's `@onclick`; component events use their PascalCase event names:
436
+ ```razor
437
+ <IgbButton @onclick="HandleClick">Save</IgbButton>
438
+ <IgbGrid RowSelectionChanging="OnRowSelection" />
439
+
440
+ @code {
441
+ private void HandleClick() { /* ... */ }
442
+ private void OnRowSelection(IgbRowSelectionEventArgs args) { /* ... */ }
443
+ }
444
+ ```
445
+
446
+ ### Template context with `<Template>`
447
+ Ignite UI Blazor uses `<Template>` child elements with the `context` parameter - not Angular's `<ng-template>`:
448
+ ```razor
449
+ <IgbGrid Data="Data">
450
+ <IgbColumn Field="Name" Header="Name">
451
+ <Template>
452
+ <div>
453
+ <strong>@context.Cell.Value</strong>
454
+ </div>
455
+ </Template>
456
+ </IgbColumn>
457
+ </IgbGrid>
458
+ ```
459
+
460
+ ### `@ref` for programmatic access
461
+ Use `@ref` with a matching field of the component type:
462
+ ```razor
463
+ <IgbDialog @ref="dialog">
464
+ <p>Dialog content</p>
465
+ </IgbDialog>
466
+
467
+ @code {
468
+ private IgbDialog dialog = default!;
469
+
470
+ private async Task ShowDialog()
471
+ {
472
+ await dialog.ShowAsync();
473
+ }
474
+ }
475
+ ```
476
+
477
+ ### C# data models - use records or classes
478
+ Use C# `record` or `class` types for mock data - not TypeScript interfaces:
479
+ ```csharp
480
+ record SalesRecord(string Month, double Revenue, double Profit);
481
+ record Contact(string Name, string Email, string Initials);
482
+ ```
483
+
484
+ ### Avoid inline styles - use CSS isolation
485
+ Keep layout, spacing, typography, and surface styling in `.razor.css` files rather than using `style=""` inline attributes. This makes theming consistent and maintainable.
486
+
487
+ ### Parameter naming: PascalCase
488
+ Blazor component parameters use PascalCase (`ChartType`, `DataSource`, `MarkerTypes`) - not Angular's camelCase bindings (`[chartType]`, `[dataSource]`, `[markerTypes]`).
489
+
490
+ ### Single quotes in Razor attribute expressions cause CS1012
491
+ In Razor, `@onclick="() => Navigate('/dashboard')"` fails because the single quotes inside the double-quoted attribute are parsed as C# `char` literals, producing error CS1012. Use a named method or a variable instead:
492
+ ```razor
493
+ @* WRONG - single quotes parsed as char literal *@
494
+ <IgbNavDrawerItem @onclick="() => Navigate('/dashboard')">
495
+
496
+ @* RIGHT - use a method reference or extract the path *@
497
+ <IgbNavDrawerItem @onclick="NavigateToDashboard">
498
+
499
+ @code {
500
+ private void NavigateToDashboard() => NavigationManager.NavigateTo("/dashboard");
501
+ }
502
+ ```
503
+ This applies to any inline lambda where a string literal containing `/` or special chars appears inside a double-quoted Razor attribute. Prefer named handler methods over inline lambdas with string arguments.