Using Blazor Components
This recipe explains how to add Blazor WebAssembly components to your Astro pages, enabling you to use .NET libraries for physics visualizations and demonstrations.
Overview
Blazor components run .NET code compiled to WebAssembly in the browser. They can coexist with React components and other page content in the same DOM, without requiring iframes.
Prerequisites
- .NET 8.0 SDK or later
- Node.js 18.x or later
- Basic understanding of Blazor and Razor syntax
Project Structure
The Blazor project lives at PAA.Blazor/ in the repository root:
PAA.Blazor/├── Components/ # Reusable Blazor components│ ├── PhysicsDemo.razor│ └── PhysicsDemo.razor.css├── Pages/ # Page components (Home.razor handles routing)├── Layout/ # Layout components (simplified, no nav)├── wwwroot/ # Static assets└── PAA.Blazor.csproj # Project fileCreating a Blazor Component
1. Create the Component File
Create a new .razor file in PAA.Blazor/Components/:
@* MyComponent.razor *@
<div class="my-component"> <h3>My Physics Demo</h3> <p>Simulation output: @value</p> <button @onclick="RunSimulation">Run</button></div>
@code { private double value = 0;
private void RunSimulation() { // Your .NET code here value = Math.PI * Math.E; }}2. Create Component Styles
Create a corresponding .razor.css file for scoped styles:
.my-component { padding: 1rem; border: 2px solid #007acc; border-radius: 8px;}
.my-component h3 { color: #007acc;}Blazor automatically scopes these styles to your component.
3. Register the Component
Automatic Registration: Components in the PAA.Blazor/Components/ directory are automatically discovered and registered during the build process. The build system scans for all .razor files and generates component-config.json automatically.
Dynamic Rendering: The Home.razor page uses Blazor’s DynamicComponent to automatically render any registered component based on the configuration file. No manual code changes needed!
@if (componentType != null){ <DynamicComponent Type="@componentType" />}The component type is resolved at runtime from the component-config.json mappings. Simply add your component to the Components/ directory and it will be automatically:
- Discovered during build
- Added to
component-config.json - Available for dynamic rendering
Note: The entire registration and rendering process is fully automated. When you add a new component to the Components/ directory, it will be automatically discovered at build time, added to component-config.json, and rendered dynamically without any code changes.
Adding to an Astro Page
1. Single Component Mode (Simple)
In your .mdx or .astro file, add a div with the component name:
<div id="blazor-root" data-component="MyComponent"></div><script src="/blazor/_framework/blazor.webassembly.js" autostart="false"></script><script src="/blazor-init.js"></script>The data-component attribute tells Blazor which component to render.
2. Multiple Components Mode (Advanced)
To display multiple Blazor components at different locations on the same page:
<!-- Define target containers for each component --><div id="physics-demo-1"></div>
<h2>Wave Simulation</h2><div id="wave-sim-1"></div>
<h2>Another Physics Demo</h2><div id="physics-demo-2"></div>
<!-- Single Blazor app renders all components --><div id="blazor-root" data-components='[ {"name":"PhysicsDemo", "targetId":"physics-demo-1"}, {"name":"WaveSimulation", "targetId":"wave-sim-1"}, {"name":"PhysicsDemo", "targetId":"physics-demo-2"}]'></div><script src="/blazor/_framework/blazor.webassembly.js" autostart="false"></script><script src="/blazor-init.js"></script>Benefits:
- Share a single Blazor runtime (~2MB) across all components
- Render multiple instances of the same component
- Place components anywhere on the page
- Each component can be positioned independently
How it works:
- The
blazor-init.jsscript reads thedata-componentsJSON array - Blazor renders all components inside
#blazor-root - JavaScript automatically moves each component to its target element
- All components share the same .NET runtime instance
3. The Component Loads Automatically
When the page loads:
- The
blazor-init.jsscript reads thedata-componentattribute (ordata-componentsfor multiple) - It passes the component information to Blazor via query parameters
- Blazor’s
Home.razorreads the parameters and renders the requested components - Components are automatically placed into their target elements
- All resources load from
/blazor/_framework/
Building and Publishing
Development
During development, run both Astro and rebuild Blazor when needed:
# Build Blazor onlynpm run build:blazor
# Start Astro dev servernpm run devProduction Build
The production build automatically compiles Blazor before Astro:
npm run buildThis:
- Compiles the Blazor project:
dotnet publish ./PAA.Blazor -c Release - Copies output to
public/blazor/ - Builds the Astro site (which copies to
dist/blazor/)
CI/CD
The GitHub Actions workflow (.github/workflows/deploy.yml) automatically:
- Installs .NET 8 SDK
- Builds the Blazor project
- Builds the Astro site
- Deploys everything to GitHub Pages
Using .NET Libraries
One of the main benefits of Blazor is access to .NET libraries:
@using System.Numerics
@code { private void CalculateComplexMath() { // Use .NET types and libraries var complex = new Complex(3.0, 4.0); var magnitude = Complex.Abs(complex);
// Use LINQ var primes = Enumerable.Range(2, 100) .Where(n => IsPrime(n)) .ToList(); }
private bool IsPrime(int n) { return Enumerable.Range(2, (int)Math.Sqrt(n) - 1) .All(i => n % i != 0); }}Best Practices
Keep Components Focused
Each component should represent a single visualization or demo. Keep the logic focused and reusable.
Use Scoped CSS
Always create a .razor.css file alongside your component for styles. This prevents conflicts with other page styles.
Handle Disposal
If your component uses timers or subscriptions, implement IDisposable:
@implements IDisposable
@code { private Timer? timer;
public void Dispose() { timer?.Dispose(); }}Performance Considerations
- Blazor loads a ~2MB runtime on first use
- The runtime is cached and reused across all Blazor components
- Multiple components mode: All components share one runtime instance, minimizing overhead
- Use the same Blazor app for multiple demos to avoid loading separate runtimes
Multiple Components
On Different Pages
You can show different components on different pages without creating multiple Blazor projects:
Page 1:
<div id="blazor-root" data-component="PhysicsDemo"></div>Page 2:
<div id="blazor-root" data-component="WaveSimulation"></div>On the Same Page
To display multiple Blazor components on a single page, use the data-components attribute with a JSON array:
<!-- Component containers --><div id="demo-1"></div><div id="demo-2"></div>
<!-- Blazor app configuration --><div id="blazor-root" data-components='[ {"name":"PhysicsDemo", "targetId":"demo-1"}, {"name":"WaveSimulation", "targetId":"demo-2"}]'></div><script src="/blazor/_framework/blazor.webassembly.js" autostart="false"></script><script src="/blazor-init.js"></script>This approach:
- Uses only one Blazor runtime (~2MB) for all components
- Allows multiple instances of the same component
- Places each component at a specific location on the page
- More efficient than loading multiple separate Blazor apps
Troubleshooting
Component Doesn’t Render
Check the browser console for errors. Common issues:
- Component name misspelled in
data-component - Component not registered in
Home.razor - Missing Blazor scripts
Styles Not Applied
- Ensure you created a
.razor.cssfile with the same name as your component - Rebuild the Blazor project after adding new CSS files
Build Fails
- Check that .NET 8 SDK is installed:
dotnet --version - Verify the Blazor project builds independently:
cd PAA.Blazor && dotnet build
Learn More
Example
See the working implementation at /demos/framework-integration which demonstrates both React and Blazor components working together.