diff --git a/docs/_pipeline/apps/styling/App.cs b/docs/_pipeline/apps/styling/App.cs
index 9d4903797..304ab4ecd 100644
--- a/docs/_pipeline/apps/styling/App.cs
+++ b/docs/_pipeline/apps/styling/App.cs
@@ -168,6 +168,15 @@ public override Element Render()
}
//
+//
+class FontFamilyResourceExample : Component
+{
+ public override Element Render() =>
+ Button("Code").Resources(r => r
+ .Set("ContentControlThemeFontFamily", new Microsoft.UI.Xaml.Media.FontFamily("Consolas")));
+}
+//
+
//
class CustomResourceExample : Component
{
diff --git a/docs/_pipeline/templates/styling.md.dt b/docs/_pipeline/templates/styling.md.dt
index 4ad626662..0e8dd2a0f 100644
--- a/docs/_pipeline/templates/styling.md.dt
+++ b/docs/_pipeline/templates/styling.md.dt
@@ -206,12 +206,28 @@ pressed, disabled) automatically respect your overrides:

-`ResourceBuilder` supports `.Set(key, ThemeRef)` for theme-reactive
-overrides, `.Set(key, string)` for hex colors, `.Set(key, double)` for
-numeric values, and `.Set(key, CornerRadius)` for corner radius.
+`ResourceBuilder.Set` has explicit overloads for `ThemeRef`, `Brush`,
+color strings, `double`, `CornerRadius`, `Thickness`, `FontWeight`,
+`FontFamily`, `bool`, and `GridLength`. Use `Thickness` for padding
+or border thickness, and `FontWeight` / `FontFamily` for typography resources.
+Literal values retain their types; `ThemeRef` overrides re-resolve on theme changes.
+
+`ResourceBuilder.SetColor(key, color)` stores a literal `Color`, not a brush.
+Use it only for Color-typed resources; brush-typed keys such as `ButtonBackground`
+need the string or `Brush` overload of `Set`. The string overload
+still parses a hex or named color into a brush; it does not store arbitrary
+text. Integer literals continue to select the `double` overload, so pass the
+value type expected by the WinUI resource key rather than relying on conversion.
Overrides cascade to child elements through WinUI's resource dictionary
hierarchy.
+Font-family resource keys require a `FontFamily` object, not a string:
+
+```csharp snippet="styling/font-family-resource"
+```
+
+Calling `Set(key, "Consolas")` would select the color-string overload instead.
+
## Custom resource access
For brushes Reactor hasn't surfaced as a typed property, `Theme.Ref()`
diff --git a/docs/guide/styling.md b/docs/guide/styling.md
index fa5bf8f82..6ba14f1f1 100644
--- a/docs/guide/styling.md
+++ b/docs/guide/styling.md
@@ -353,12 +353,34 @@ class LightweightStylingExample : Component

-`ResourceBuilder` supports `.Set(key, ThemeRef)` for theme-reactive
-overrides, `.Set(key, string)` for hex colors, `.Set(key, double)` for
-numeric values, and `.Set(key, CornerRadius)` for corner radius.
+`ResourceBuilder.Set` has explicit overloads for `ThemeRef`, `Brush`,
+color strings, `double`, `CornerRadius`, `Thickness`, `FontWeight`,
+`FontFamily`, `bool`, and `GridLength`. Use `Thickness` for padding
+or border thickness, and `FontWeight` / `FontFamily` for typography resources.
+Literal values retain their types; `ThemeRef` overrides re-resolve on theme changes.
+
+`ResourceBuilder.SetColor(key, color)` stores a literal `Color`, not a brush.
+Use it only for Color-typed resources; brush-typed keys such as `ButtonBackground`
+need the string or `Brush` overload of `Set`. The string overload
+still parses a hex or named color into a brush; it does not store arbitrary
+text. Integer literals continue to select the `double` overload, so pass the
+value type expected by the WinUI resource key rather than relying on conversion.
Overrides cascade to child elements through WinUI's resource dictionary
hierarchy.
+Font-family resource keys require a `FontFamily` object, not a string:
+
+```csharp
+class FontFamilyResourceExample : Component
+{
+ public override Element Render() =>
+ Button("Code").Resources(r => r
+ .Set("ContentControlThemeFontFamily", new Microsoft.UI.Xaml.Media.FontFamily("Consolas")));
+}
+```
+
+Calling `Set(key, "Consolas")` would select the color-string overload instead.
+
## Custom resource access
For brushes Reactor hasn't surfaced as a typed property, `Theme.Ref()`
diff --git a/docs/specs/002-winui3-gap-analysis.md b/docs/specs/002-winui3-gap-analysis.md
index 2b0bf7468..8668c58dc 100644
--- a/docs/specs/002-winui3-gap-analysis.md
+++ b/docs/specs/002-winui3-gap-analysis.md
@@ -471,7 +471,7 @@ by conditional rendering — elements not returned from render are never created
| WinUI Feature | Status | Notes |
|---|---|---|
| **ResourceDictionary (app-level)** | Passthrough | ReactorApp loads XamlControlsResources; no DSL for authoring app-level dictionaries |
-| **ResourceDictionary (per-element)** | Exposed | `.Resources(r => r.Set(key, value))` writes into that element's own `FrameworkElement.Resources`; `ResourceBuilder.Set` overloads accept a hex/named color string, a `Brush`, a `ThemeRef`, a `double`, or a `CornerRadius` |
+| **ResourceDictionary (per-element)** | Exposed | `.Resources(r => r.Set(key, value))` writes into that element's own `FrameworkElement.Resources`; `Set` accepts color strings, `Brush`, `ThemeRef`, `double`, `CornerRadius`, `Thickness`, `FontWeight`, `FontFamily`, `bool`, and `GridLength`. `SetColor` stores raw `Color` values, not brushes |
| **Resource lookup chain** | Passthrough | WinUI's chain works on underlying controls; a per-element override participates in it normally |
| **Merged dictionaries** | Passthrough | Can merge via `.Set()` on Application.Resources |
| **Theme dictionaries** | Passthrough | WinUI's theme dictionaries work natively; `ThemeRef` resolution reads through them |
diff --git a/docs/specs/015-styling-design.md b/docs/specs/015-styling-design.md
index 8e3e1828c..e6b4a94d0 100644
--- a/docs/specs/015-styling-design.md
+++ b/docs/specs/015-styling-design.md
@@ -271,6 +271,15 @@ public class ResourceBuilder
return this;
}
+ public ResourceBuilder Set(string key, Thickness value) { _resources[key] = value; return this; }
+ public ResourceBuilder Set(string key, FontWeight value) { _resources[key] = value; return this; }
+ public ResourceBuilder Set(string key, FontFamily value) { _resources[key] = value; return this; }
+ public ResourceBuilder Set(string key, bool value) { _resources[key] = value; return this; }
+ public ResourceBuilder Set(string key, GridLength value) { _resources[key] = value; return this; }
+
+ // Literal Color resources only. Brush-typed resources use Set(string/Brush/ThemeRef).
+ public ResourceBuilder SetColor(string key, Color value) { _resources[key] = value; return this; }
+
internal ResourceOverrides Build() => new(_resources, _themeResources);
}
diff --git a/docs/specs/tasks/styling-implementation.md b/docs/specs/tasks/styling-implementation.md
index 851a569d9..88a7f5e1c 100644
--- a/docs/specs/tasks/styling-implementation.md
+++ b/docs/specs/tasks/styling-implementation.md
@@ -156,6 +156,12 @@ competitive advantage — no other C# declarative framework surfaces this.
- [x] `Set(string key, ThemeRef themeRef)` — stores for reactive resolution
- [x] `Set(string key, double value)` — for numeric resource keys
- [x] `Set(string key, CornerRadius value)` — for corner radius keys
+ - [x] `Set(string key, Thickness value)` — padding and border thickness
+ - [x] `Set(string key, FontWeight value)` — font weight
+ - [x] `Set(string key, FontFamily value)` — font family, compared by Source
+ - [x] `Set(string key, bool value)` — Boolean resources
+ - [x] `Set(string key, GridLength value)` — grid length resources
+ - [x] `SetColor(string key, Color value)` — raw Color only, not a Brush
- [x] `internal ResourceOverrides Build()` — returns immutable snapshot
### 4.2 — ResourceOverrides record
diff --git a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
index fbf6b92ce..727191aee 100644
--- a/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
+++ b/plugins/reactor/skills/reactor-dsl/references/reactor.api.txt
@@ -4902,9 +4902,15 @@ ToString() → string
new()
Set(string key, Brush brush) → ResourceBuilder
Set(string key, CornerRadius value) → ResourceBuilder
+Set(string key, FontFamily value) → ResourceBuilder
+Set(string key, FontWeight value) → ResourceBuilder
+Set(string key, GridLength value) → ResourceBuilder
Set(string key, ThemeRef themeRef) → ResourceBuilder
+Set(string key, Thickness value) → ResourceBuilder
+Set(string key, bool value) → ResourceBuilder
Set(string key, double value) → ResourceBuilder
Set(string key, string color) → ResourceBuilder
+SetColor(string key, Color value) → ResourceBuilder
### record ResourceOptions
new(TimeSpan? StaleTime = null, TimeSpan? CacheTime = null, int RetryCount = 0, bool RefetchOnMount = true, string CacheKey = null, bool RefetchOnWindowFocus = false)
diff --git a/skills/reactor.api.txt b/skills/reactor.api.txt
index fbf6b92ce..727191aee 100644
--- a/skills/reactor.api.txt
+++ b/skills/reactor.api.txt
@@ -4902,9 +4902,15 @@ ToString() → string
new()
Set(string key, Brush brush) → ResourceBuilder
Set(string key, CornerRadius value) → ResourceBuilder
+Set(string key, FontFamily value) → ResourceBuilder
+Set(string key, FontWeight value) → ResourceBuilder
+Set(string key, GridLength value) → ResourceBuilder
Set(string key, ThemeRef themeRef) → ResourceBuilder
+Set(string key, Thickness value) → ResourceBuilder
+Set(string key, bool value) → ResourceBuilder
Set(string key, double value) → ResourceBuilder
Set(string key, string color) → ResourceBuilder
+SetColor(string key, Color value) → ResourceBuilder
### record ResourceOptions
new(TimeSpan? StaleTime = null, TimeSpan? CacheTime = null, int RetryCount = 0, bool RefetchOnMount = true, string CacheKey = null, bool RefetchOnWindowFocus = false)
diff --git a/src/Reactor/Core/Element.cs b/src/Reactor/Core/Element.cs
index c3a046ed9..4bb7dd447 100644
--- a/src/Reactor/Core/Element.cs
+++ b/src/Reactor/Core/Element.cs
@@ -1498,8 +1498,8 @@ internal static bool ResourceOverridesEqual(
// Literals: compare by VALUE. Brushes are re-parsed to fresh instances each render
// (e.g. .Set("X", "#0078D4")), so reference compare would false-decline the skip for
- // an UNCHANGED literal-override cell — use BrushesEqual; other literal kinds (double,
- // CornerRadius) are value types whose Equals is correct.
+ // an UNCHANGED literal-override cell. FontFamily also compares by value (Source),
+ // not WinRT wrapper identity. The remaining literal kinds are value types.
var la = a.Literals;
var lb = b.Literals;
if (la.Count != lb.Count) return false;
@@ -1526,6 +1526,8 @@ private static bool ResourceLiteralEqual(object? a, object? b)
if (ReferenceEquals(a, b)) return true;
if (a is null || b is null) return false;
if (a is Brush ba && b is Brush bb) return BrushesEqual(ba, bb);
+ if (a is Microsoft.UI.Xaml.Media.FontFamily fa && b is Microsoft.UI.Xaml.Media.FontFamily fb)
+ return FontFamiliesEqual(fa, fb);
return a.Equals(b);
}
}
diff --git a/src/Reactor/Elements/ResourceBuilder.cs b/src/Reactor/Elements/ResourceBuilder.cs
index c45a049db..4aecea649 100644
--- a/src/Reactor/Elements/ResourceBuilder.cs
+++ b/src/Reactor/Elements/ResourceBuilder.cs
@@ -1,12 +1,14 @@
using Microsoft.UI.Reactor.Core;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
+using Windows.UI;
+using Windows.UI.Text;
namespace Microsoft.UI.Reactor.Elements;
///
/// Immutable snapshot of per-control resource overrides built by .
-/// Contains both literal values (colors, doubles, corner radii) and theme-reactive
+/// Contains both literal resource values and theme-reactive
/// entries that are re-resolved on theme change.
///
public sealed record ResourceOverrides(
@@ -64,7 +66,7 @@ public ResourceBuilder Set(string key, ThemeRef themeRef)
return this;
}
- /// Sets a numeric resource override (e.g., ButtonBorderThemeThickness).
+ /// Sets a numeric resource override (e.g., BreadcrumbBarItemThemeFontSize).
public ResourceBuilder Set(string key, double value)
{
_literals[key] = value;
@@ -78,6 +80,51 @@ public ResourceBuilder Set(string key, CornerRadius value)
return this;
}
+ /// Sets a thickness resource override (e.g., BreadcrumbBarChevronPadding).
+ public ResourceBuilder Set(string key, Thickness value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a font weight resource override (e.g., BreadcrumbBarItemFontWeight).
+ public ResourceBuilder Set(string key, FontWeight value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a font family resource override (e.g., ContentControlThemeFontFamily).
+ public ResourceBuilder Set(string key, FontFamily value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a Boolean resource override (e.g., GridViewItemSelectionCheckMarkVisualEnabled).
+ public ResourceBuilder Set(string key, bool value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ ///
+ /// Sets a literal color resource override, not a brush. Use the string or
+ /// overload for resources that expect a brush.
+ ///
+ public ResourceBuilder SetColor(string key, Color value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
+ /// Sets a grid length resource override (e.g., ContentDialogButtonSpacing).
+ public ResourceBuilder Set(string key, GridLength value)
+ {
+ _literals[key] = value;
+ return this;
+ }
+
/// Builds an immutable snapshot.
internal ResourceOverrides Build()
{
diff --git a/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs b/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs
new file mode 100644
index 000000000..75673bb3e
--- /dev/null
+++ b/tests/Reactor.AppTests.Host/SelfTest/Fixtures/TypedResourceOverrideFixtures.cs
@@ -0,0 +1,139 @@
+using Microsoft.UI.Reactor.Core;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Automation;
+using Microsoft.UI.Xaml.Media;
+using static Microsoft.UI.Reactor.Factories;
+
+namespace Microsoft.UI.Reactor.AppTests.Host.SelfTest.Fixtures;
+
+internal static class TypedResourceOverrideFixtures
+{
+ internal sealed class MountUpdateAndRemoval(Harness h) : SelfTestFixtureBase(h)
+ {
+ public override async Task RunAsync()
+ {
+ var family = new FontFamily("Consolas");
+ var updatedFamily = new FontFamily("Segoe UI");
+ Action? setPhase = null;
+ var host = H.CreateHost();
+ host.Mount(ctx =>
+ {
+ var (phase, update) = ctx.UseState(0);
+ setPhase = update;
+ var element = Button("typed resource overrides");
+ if (phase < 2)
+ element = element.Resources(r => r
+ .Set("TypedPadding", Padding(phase))
+ .Set("TypedWeight", new global::Windows.UI.Text.FontWeight((ushort)(phase == 0 ? 700 : 400)))
+ .Set("TypedFont", phase == 0 ? family : updatedFamily)
+ .Set("TypedBoolean", phase == 0)
+ .SetColor("TypedColor", Color(phase))
+ .Set("TypedGridLength", Length(phase))
+ .Set("TypedBrush", "#123456"));
+ return element;
+ });
+
+ await Harness.Render();
+ var control = H.FindControl