maui-accessibility
Guide for making .NET MAUI apps accessible — screen reader support via SemanticProperties, heading levels, AutomationProperties…
Guidance for embedding web content in .NET MAUI apps using HybridWebView, including JavaScript–C# interop, bidirectional communication, raw messaging, and trimming/NativeAOT considerations. USE FOR: "HybridWebView", "JavaScript interop", "embed web content", "JS to C# interop",
$ npx -y skills add davidortinau/maui-skills --skill maui-hybridwebview --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maui-hybridwebviewContext preview
The summary Claude sees to decide when to auto-load this skill.
Guidance for embedding web content in .NET MAUI apps using HybridWebView, including JavaScript–C# interop, bidirectional communication, raw messaging, and trimming/NativeAOT considerations. USE FOR: "HybridWebView", "JavaScript interop", "embed web content", "JS to C# interop",
name: maui-hybridwebview description: > Guidance for embedding web content in .NET MAUI apps using HybridWebView, including JavaScript–C# interop, bidirectional communication, raw messaging, and trimming/NativeAOT considerations. USE FOR: "HybridWebView", "JavaScript interop", "embed web content", "JS to C# interop", "C# to JavaScript", "web view interop", "raw message", "InvokeJavaScriptAsync", "web content MAUI". DO NOT USE FOR: deep linking from external URLs (use maui-deep-linking), REST API calls (use maui-rest-api), or Blazor Hybrid apps (different from HybridWebView).
`HybridWebView` hosts HTML/JS/CSS content inside a .NET MAUI app with bidirectional C#↔JS communication. It is **not** a general browser control — it is designed for local web content shipped with the app.
| Issue | Fix | |---|---| | Blank white screen | Web assets missing from `Resources/Raw/wwwroot` or `DefaultFile` not set | | JS interop silently fails | Missing `<script src="_hwv/HybridWebView.js"></script>` in HTML | | `InvokeJavaScriptAsync` returns null | Return type missing `[JsonSerializable]` attribute in `JsonSerializerContext` | | JS → C# calls do nothing | `SetInvokeJavaScriptTarget` not called before JS invokes C# methods | | Serialization crash with trimming | Not using source-generated `JsonSerializerContext` |
The HTML page **must** include the bridge script **before** any app scripts:
<!-- ✅ Correct order --> <script src="_hwv/HybridWebView.js"></script> <script src="scripts/app.js"></script> <!-- ❌ Wrong — app.js loads before bridge, interop calls fail silently --> <script src="scripts/app.js"></script> <script src="_hwv/HybridWebView.js"></script>
Every parameter type **and** return type used in `InvokeJavaScriptAsync` must have a `[JsonSerializable]` entry:
// ✅ Correct — all interop types registered
[JsonSerializable(typeof(int))]
[JsonSerializable(typeof(string))]
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext { }
// ❌ Wrong — adding a new type to interop without registering it
// This causes silent null returns or runtime exceptions> **Rule**: When you add a new type to the interop surface, you **must** add a `[JsonSerializable(typeof(T))]` attribute to the context. Forgetting this is the #1 cause of mysterious interop failures.
// ✅ Set target BEFORE the web page loads and JS calls C# myHybridWebView.SetInvokeJavaScriptTarget(new MyJsBridge()); // ❌ Setting it after JS already tried to call — calls are lost
⚠️ Call `SetInvokeJavaScriptTarget` during page construction or `OnAppearing`, not lazily.
JS exceptions thrown during `InvokeJavaScriptAsync` are forwarded to .NET. Always wrap interop calls:
// ✅ Catches JS errors
try
{
var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
"riskyFunction", MyJsonContext.Default.String);
}
catch (Exception ex)
{
Debug.WriteLine($"JS error: {ex.Message}");
}
// ❌ Unhandled JS exception crashes the interop pipeline
var result = await myHybridWebView.InvokeJavaScriptAsync<string>(
"riskyFunction", MyJsonContext.Default.String);Trimming is **disabled by default** in MAUI projects. If you enable it:
<PropertyGroup> <PublishTrimmed>true</PublishTrimmed> <JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault> </PropertyGroup>
| Need | Use | |---|---| | Structured data exchange with type safety | `InvokeJavaScriptAsync` / `InvokeDotNet` with `JsonSerializerContext` | | Simple string payloads, fire-and-forget | `SendRawMessage` / `RawMessageReceived` | | Calling C# from JS with return values | `InvokeDotNet` (target must be set first) | | Multiple JS functions to call | Typed interop — one `InvokeJavaScriptAsync` per function |
A collection of 41 skills for .NET MAUI development, UI/UX design reasoning, and Xamarin migration, designed for use with GitHub Copilot CLI and Claude Code.
Guide for making .NET MAUI apps accessible — screen reader support via SemanticProperties, heading levels, AutomationProperties…
.NET MAUI view animations, custom animations, easing functions, rotation, scale, translation, and fade effects. USE FOR: "animate…
.NET MAUI app icon configuration, splash screen setup, SVG to PNG conversion at build time, composed/adaptive icons, and…
.NET MAUI app lifecycle guidance covering the four app states (not running, running, deactivated, stopped), cross-platform Window…
Guide for .NET MAUI apps consuming .NET Aspire-hosted backend services. Covers AppHost configuration, service discovery for…
Add authentication to .NET MAUI apps. Covers WebAuthenticator for generic OAuth 2.0 / social login, and MSAL.NET for Microsoft…